RSpec vs Test :: Unit в Rails

15

Я никогда не был убежден в преимуществах, которые вы получаете, переключаясь на RSpec из Test :: Unit в Ruby on Rails (несмотря на то, что время от времени читаете о RSpec).

Что в RSpec, по-видимому, используется в большинстве проектов Rails?

(некоторые примеры кода, четко указывающие на преимущества одного над другим, будут высоко оценены)

Павел Гольчицкий
источник
4
Только через год, и я с отвращением смотрю на Test :: Unit ... RSpec FTW!
Павел Гольчицкий
Около дубликатов в StackOverflow: RSpec vs Test :: Unit и RSpec vs
musta

Ответы:

13

Это в значительной степени дело вкуса, и большинство инструментов для тестирования того стоят. Мое личное предпочтение - RSpec, а не Test :: Unit, потому что а) вывод и компоновка тестов фокусируются на том, что должен делать тестируемый объект (в отличие от того, что представляет собой код), и б) говорят «Х должен Y» имеет больше смысла для меня, чем «утверждать, что X предикат Y».

Чтобы дать вам некоторый контекст для вышеприведенных пунктов, вот (довольно надуманное) сравнение выходного / исходного кода двух функционально эквивалентных модульных тестов, один из которых написан с использованием RSpec, а другой - с помощью Test :: Unit.

Тестируемый код

class DeadError < StandardError; end

class Dog
  def bark
    raise DeadError.new "Can't bark when dead" if @dead
    "woof"
  end

  def die
    @dead = true
  end
end

Test :: Unit

 require 'test/unit'
  require 'dog'

  class DogTest < Test::Unit::TestCase
    def setup
      @dog = Dog.new
    end

    def test_barks
      assert_equal "woof", @dog.bark    
    end

    def test_doesnt_bark_when_dead
      @dog.die
      assert_raises DeadError do
        @dog.bark
      end
    end
  end

RSpec

require 'rspec'
require 'dog'

describe Dog do
  before(:all) do
    @dog = Dog.new
  end

  context "when alive" do
    it "barks" do
      @dog.bark.should == "woof"
    end
  end

  context "when dead" do
    before do
      @dog.die
    end

    it "raises an error when asked to bark" do
      lambda { @dog.bark }.should raise_error(DeadError)
    end
  end
end

Test :: Unit output (настолько полный, насколько я мог это сделать)

Ξ code/examples → ruby dog_test.rb --verbose
Loaded suite dog_test
Started
test_barks(DogTest): .
test_doesnt_bark_when_dead(DogTest): .

Finished in 0.004937 seconds.

Вывод RSpec (форматирование документации)

Ξ code/examples → rspec -fd dog_spec.rb 

Dog
  when alive
    barks
  when dead
    raises an error when asked to bark

Finished in 0.00224 seconds
2 examples, 0 failures

2 tests, 2 assertions, 0 failures, 0 errors

PS Я думаю, что Берин (предыдущий респондент) совмещает роли Cucumber (который вырос из проекта RSpec, но является независимым) и RSpec. Cucumber - это инструмент для автоматического приемочного тестирования в стиле BDD, тогда как RSpec - это библиотека кодов для тестирования, которая может использоваться и используется на единичном, интеграционном и функциональном уровнях. Следовательно, использование RSpec не исключает модульного тестирования - просто вы называете свои модульные тесты «спецификациями».

долбить
источник
Не ожидал, что будет грустно, когда я приехал сюда
Роман
3

В последнее время кажется, что Cucumber получает больше поддержки в сообществе Rails. Вот краткий аргумент, который я услышал в интервью с ведущим RSpec (из старого подкаста Ruby on Rails).

В гибком сообществе (в то время) был большой толчок для разработки, основанной на тестировании, с упором на тестирование в первую очередь, чтобы доказать, что вам нужно что-то изменить. С этим было что-то философски неправильно. По сути, тестирование - это способ убедиться, что ваша реализация верна, так как вы по-другому относитесь к дизайну вождения? Руководство RSpec предположило, что вы укажете в первую очередь, и не будет ли замечательно, если спецификация также проверит результаты вашей реализации?

Простое переименование assertв shouldпомогает сосредоточить ум на правильном пути к спецификации записи, и думать о дизайне. Тем не менее, это только часть уравнения.

Что еще более важно, поскольку многие сторонники TDD утверждали, что тесты документировали проект, большинство документации было в лучшем случае плохим. Тесты довольно непрозрачны для не-разработчиков, незнакомых с языком. Даже тогда дизайн не сразу бросается в глаза после прочтения большинства тестов.

Поэтому в качестве вторичной цели RSpec разработал способ создания письменной документации на основе спецификаций. Именно эта письменная спецификация дает RSpec преимущество над простым Test :: Unit для управления дизайном приложения. Зачем писать что-то более одного раза, когда вы можете одновременно документировать и проверять согласованность проекта?

Насколько я понимаю, что Cucumber, который получил преимущество, придя позже и выучив уроки в RSpec, лучше справляется с этой вторичной целью, не теряя при этом основной цели (способность тестировать реализацию по спецификации). Cucumber делает это с помощью достаточно похожего на английский API, который могут запрограммировать непрограммисты. Им могут понадобиться помощь программистов, чтобы заполнить некоторые определения новых методов проверки, но они предназначены для расширения.

Суть в том, что RSpec / Cucumber не должны полностью заменять модульное тестирование. Они могут лучше подходить для документирования и проверки вашего проекта, но есть еще несколько тестов реализации, которые все еще необходимо выполнить, особенно с небольшими ошибками, которые связаны с реализацией, а не с дизайном приложения. Это уменьшает количество тестов, которые вы должны написать.

Берин Лорич
источник