3

CSV ファイルを読み取るメソッドをテストするために、File.open をスタブしようとしています。

モデルは次のとおりです。

class BatchTask
  def import(filename)
    CSV.read(filename, :row_sep => "\r", :col_sep => ",")
  end
end

仕様コードは次のとおりです。

let(:data) { "title\tsurname\tfirstname\rtitle2\tsurname2\tfirstname2\r"}
let(:result) {[["title","surname","firstname"],["title2","surname2","firstname2"]] }

it "should parse file contents and return a result" do
  File.stub(:open).with("file_name","rb") { StringIO.new(data) }
  person.import("file_name").should == result
end

ただし、これを実行しようとすると、次のようになります(スタックトレース):

Errno::ENOENT in 'BatchTask should parse file contents and return a result'
No such file or directory - file_name
/Users/me/app/models/batch_task.rb:4:in `import'
./spec/models/batch_task_spec.rb:10:

Finished in 0.006032 seconds

私はこれに頭をぶつけてきましたが、何が間違っているのかわかりません。どんな助けでも大歓迎です!

4

1 に答える 1

9

なぜそれが起こるのか推測しますが、スタックトレースを提供すると役に立ちます。また、ここでのアプローチは良くないと思います。テストする方法について詳しく説明します。

CSV.readただ、使わないと思いますFile.openKernel#openRubyでファイルを開くことができる他のさまざまな方法を使用できます。File.openとにかく、このようにテストでスタブするべきではありません。

テストによって導かれるオブジェクト指向ソフトウェアの成長と呼ばれる素晴らしい本があり、必要なルールがあります:

制御するクラス/インターフェースのスタブのみのメソッド

それには非常に単純な理由があります。テスト double (スタブ) を実行するときの主な理由は、インターフェイスの発見です。クラスのインターフェイスがどのように見えるかを理解し、double が適切なフィードバックを提供することを望んでいます。2 つ目の理由もあります。外部ライブラリのスタブは、場合によっては非常にトリッキーになる傾向があります (ライブラリが極端にスタブ可能でない場合)。したがって、ここでいくつかの異なるアプローチを取ることができます。

  1. 統合でテストできます。各テストでファイルを作成し、パス名を渡すことができます (これで問題ありません)。
  2. 解析方法を分解できます。にファイル名を渡す代わりにCSV.read、open を渡す方法を見つけてからFile、テストでそれをスタブします。つまり、コードで の代わりにファイルを開きますCSV。そうすれば簡単にスタブできます
  3. CSV.read代わりにスタブ。これは少し劇的かもしれませんが、本質的には、コードをテストしているのではなく、CSVライブラリをテストしているのです。独自のテストが既にあるはずであり、とにかくテストする必要はありません。代わりに、それが機能するという事実に依存して、呼び出しをスタブするだけです。

その中で、私はおそらく3番目のものを選びます。単体テストで依存関係をテストするのは好きではありません。ただし、テストでそのコードを呼び出す場合は、2 番目のオプションを実行する方法を見つけることをお勧めします (CSV.new(file)トリックを実行する必要がありますが、調査する時間がありません)。他に何も機能しない場合は、最終的に #1 にフォールバックします。

于 2012-07-27T17:36:11.510 に答える