RSpec издевается над: каждый блок - PullRequest
7 голосов
/ 18 декабря 2008

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

Ruby:

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 = немного помогает, но как-то не так.

Ответы [ 4 ]

8 голосов
/ 03 июля 2012

Чтобы понять, как работает «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' для проверки вывода этих блоков.

4 голосов
/ 18 декабря 2008

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

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

2 голосов
/ 19 декабря 2008

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

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

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

1 голос
/ 20 декабря 2008

Это должно сработать:

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 (он не пройдет тест), но так я бы написал тест.

...