8

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

R仕様:

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=')

ルビーコードでそれを self.extracted= に置き換えると、少しは役に立ちますが、どういうわけか間違っているように感じます。

4

4 に答える 4

9

「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」を使用して「each」型ブロックへの入力をモックします。これらのブロックの出力をモックするには、「and_return」を使用します。

于 2012-07-03T14:11:23.237 に答える
4

これを確認できる Ruby と RSpec を備えたコンピューターはありませんがand_yieldsshould_receive(:each). ただし、この場合はモックを使用しない方が簡単な場合があります。たとえば、スタブからStringIO含まれるインスタンスを返すことができます。linetextFile.open

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

于 2008-12-18T17:40:27.970 に答える
2

File.open呼び出しをスタブするというアイデアを採用します

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

これは、ループ内のコードをテストするのに十分なはずです。

于 2008-12-18T22:35:05.457 に答える
1

これでうまくいくはずです:

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

パーサークラスにはいくつかのバグがあります(テストに合格しません)が、それが私がテストを書く方法です。

于 2008-12-20T17:43:51.827 に答える