RSpec насмехается над: каждый блок

Я хочу использовать макеты RSpec, чтобы обеспечить постоянный ввод в блок.

Рубин:

class Parser
  attr_accessor :extracted

  def parse(fname)
    File.open(fname).each do |line|
      extracted = line if line =~ /^RCS file: (.*),v$/
    end
  end
end

RSpec:

describe Parser
  before do
    @parser = Parser.new
    @lines = mock("lines")
    @lines.stub!(:each)
    File.stub!(:open).and_return(@lines)
  end

  it "should extract a filename into extracted" do
    linetext = [ "RCS file: hello,v\n", "bla bla bla\n" ]

    # HELP ME HERE ...
    # the :each should be fed with 'linetext'
    @lines.should_receive(:each)

    @parser.should_receive('extracted=')
    @parser.parse("somefile.txt")
  end
end

Это способ проверить правильность работы внутреннего устройства блока, передав в него фиксированные данные. Но я не могу понять, как выполнить фактическую подачу с помощью механизма фиксации RSpec.

Обновить: похоже, что проблема была не в строчном тексте, а в:

@parser.should_receive('extracted=')

это не так, как он называется, замена его в коде ruby ​​на self.extracted = немного помогает, но почему-то кажется неправильным.

Одна извлекаемая ошибка должна быть переменной экземпляра, @extracted. См. Мой комментарий для правильного теста.

titanous 22.12.2008 04:48
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
8
1
8 325
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

У меня нет компьютера с доступными Ruby и RSpec, чтобы проверить это, но я подозреваю, что вам нужно добавить вызов к and_yields call [1] на конце should_receive(:each). Однако вам может быть проще не использовать mocks в этом случае, например. вы можете вернуть экземпляр StringIO, содержащий linetext, из заглушки File.open.

[1] http://rspec.rubyforge.org/rspec/1.1.11/classes/Spec/Mocks/BaseExpectation.src/M000104.html

and_yields не делает то, что мне нужно, а если и делает - тогда я просто не могу понять, как, черт возьми, это работает.

Evgeny 18.12.2008 22:25

Нет, ты прав. Похоже, что моя ошибка на самом деле находится в @ parser.should_receive ('extract ='). это просто не правильно ... не работает.

Evgeny 18.12.2008 22:29

Когда я заменил "extract = " на "self.extracted = " в коде Ruby, он начал работать правильно. Последние два дня гнался не за тем багом.

Evgeny 18.12.2008 22:47

Я бы пошел с идеей заглушить вызов File.open

lines = "RCS file: hello,v\n", "bla bla bla\n"
File.stub!(:open).and_return(lines)

Этого должно быть достаточно для проверки кода внутри цикла.

Это должно помочь:

describe Parser
  before do
    @parser = Parser.new
  end

  it "should extract a filename into extracted" do
    linetext = [ "RCS file: hello,v\n", "bla bla bla\n" ]
    File.should_receive(:open).with("somefile.txt").and_return(linetext)
    @parser.parse("somefile.txt")
    @parser.extracted.should == "hello"
  end
end

В классе Parser есть некоторые ошибки (он не проходит тест), но я бы написал тест именно так.

Чтобы конкретизировать, как работает «and_yield»: я не думаю, что «and_return» - это действительно то, что вам здесь нужно. Это установит возвращаемое значение блока File.open, а не строки, переданные его блоку. Чтобы немного изменить пример, скажите, что у вас есть это:

Рубин

def parse(fname)
  lines = []
  File.open(fname){ |line| lines << line*2 }
end

Rspec

describe Parser do
  it 'should yield each line' do
    File.stub(:open).and_yield('first').and_yield('second')
    parse('nofile.txt').should eq(['firstfirst','secondsecond'])
  end
end

Пройдешь. Если вы заменили эту строку на 'and_return', например

File.stub(:open).and_return(['first','second'])

Это не удастся, потому что блокировка обходится:

expected: ["firstfirst", "secondsecond"]
got: ["first", "second"]

Таким образом, нижняя строка - это использование and_yield для имитации ввода в блоки типа «каждый». Используйте and_return, чтобы имитировать вывод этих блоков.

Другие вопросы по теме