Заглушка File.open с помощью Rspec

Я пытаюсь заглушить File.open, чтобы протестировать метод, который у меня есть, который читает файл CSV.

Вот модель:

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

Однако, когда я пытаюсь это сделать, я получаю (stacktrace):

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

Я стучал головой об этот и не могу понять, что я делаю неправильно. Любая помощь будет принята с благодарностью!


person Sly    schedule 27.07.2012    source источник
comment
добавлена ​​трассировка стека с точной ошибкой   -  person Sly    schedule 27.07.2012


Ответы (1)


Было бы полезно предоставить трассировку стека, хотя я сделаю предположение, почему это происходит. Кроме того, я считаю, что ваш подход здесь не очень хорош, и я подробно расскажу о том, как, по моему мнению, вам следует тестировать.

Просто я думаю, что CSV.read не использует File.open. Он может использовать Kernel#open или другие способы открытия файла в Ruby. В любом случае вы не должны заглушать File.open в тесте.

Есть отличная книга под названием Growing Object-Oriented Software Guided by Tests, в которой есть правило потребности:

Заглушить только методы классов/интерфейсов, которыми вы управляете

Тому есть очень простая причина. Когда вы делаете тестовые двойники (заглушки), основной причиной является обнаружение интерфейса — вы хотите выяснить, как должен выглядеть интерфейс вашего класса, а двойники предоставляют вам аккуратную обратную связь. Есть и второстепенная причина: в некоторых случаях заглушка внешних библиотек может быть довольно сложной задачей (когда библиотека не является чрезвычайно заглушенной). Таким образом, вы можете использовать несколько разных подходов, которые я перечислю:

  1. Вы можете протестировать интеграцию. Вы можете создать файл в каждом тесте и передать путь (это нормально).
  2. Вы можете разбить способ синтаксического анализа. Вместо того, чтобы передавать имя файла в CSV.read, найдите способ, когда вы передаете открытый File, а затем заглушите его в тесте. т. е. пусть ваш код открывает файл вместо CSV. Таким образом, вы можете легко заглушить его
  3. Вместо этого заглушка CSV.read. Это может быть немного драматично, но по сути вы тестируете не свой код, вы тестируете библиотеку CSV. У него уже должны быть свои тесты, и вам все равно не нужно его тестировать. Вместо этого вы можете положиться на то, что он работает, и просто заглушить его вызов.

Из них я бы, наверное, пошел с третьим. Я не люблю тестировать зависимости в своих модульных тестах. Но если вы хотите, чтобы ваш тест вызывал этот код, я предлагаю найти способ сделать второй вариант (CSV.new(file) должен помочь, но у меня нет времени на расследование) и, наконец, вернуться к # 1, если ничего не работает.

person Stefan Kanev    schedule 27.07.2012
comment
спасибо за очень содержательный ответ! Это определенно дало мне хорошую перспективу, чтобы подумать о том, как двигаться дальше. Заглушка метода CSV.read кажется лучшим способом. Спасибо еще раз! - person Sly; 30.07.2012