Несколько операторов должны в одном rspec это предложение - плохая идея?
Здесь мой тест rspec:
it "can release an idea" do
james.claim(si_title)
james.release(si_title)
james.ideas.size.should eq 0
si_title.status.should eq "available"
end
Являются ли две строки should
в конце очень плохой идеей? Я где-то читал, что вы должны проверять только одну вещь на блок it
, но кажется глупым сделать целый тест, чтобы убедиться, что статус заголовка изменился (одна и та же функция выполняет обе вещи в моем коде).
Ответы
Ответ 1
Моя интерпретация этого заключается не столько в том, что должно быть ровно одно утверждение/вызов should
для каждой спецификации, но должно быть только один бит поведения, проверенный на спецификацию, так например
it 'should do foo and bar' do
subject.do_foo.should be_true
subject.do_bar.should be_true
end
плохо - вы одновременно указываете 2 разных поведения.
с другой стороны, если ваши 2 утверждения просто проверяют разные аспекты одной вещи, тогда я в порядке с этим, например
it 'should return a prime integer' do
result = subject.do_x
result.should be_a(Integer)
result.foo.should be_prime
end
Для меня не было бы лишнего смысла иметь одну спецификацию, которая проверяет, возвращает ли она целое и отдельное, которое возвращает простое.
Конечно, в этом случае совпадение be_prime может легко выполнить обе эти проверки - возможно, хорошее эмпирическое правило состоит в том, что несколько утверждений в порядке, если вы могли бы разумно сократить их до 1 с помощью специального совпадения (действительно ли это делается фактически стоит, вероятно, зависит от вашей ситуации)
В вашем конкретном случае можно утверждать, что в игре есть 2 поведения: один изменяет статус, а другой мутирует коллекцию ideas
. Я бы пересказывал ваши спецификации, чтобы сказать, что должен сделать метод выпуска -
it 'should change the status to available'
it 'should remove the idea from the claimants ideas'
В настоящее время эти вещи всегда происходят одновременно, но я бы сказал, что они являются отдельными поведением - вы можете легко представить себе систему, в которой несколько человек могут претендовать/выпустить идею, а статус изменяется только тогда, когда последний человек выпускает идею.
Ответ 2
У меня такая же проблема...
Должно быть, каждый должен за него (говорит мой босс), заставляя тестировать время и, как вы сказали, глупо.
Тесты требуют здравого смысла и гибкости, иначе они могут поработить вас.
Во всяком случае, я согласен с вашим тестом.
Ответ 3
Моя политика заключается в том, чтобы всегда рассматривать множественные утверждения как признак потенциальной проблемы и заслуживать второй мысли, но не обязательно неправильно. Вероятно, 1/3 спецификации, которую я пишу, в конечном итоге имеют несколько утверждений в них по той или иной причине.
Одна из проблем с множественными утверждениями заключается в том, что когда кто-то терпит неудачу, вы не можете видеть, прошел ли другой или нет. Иногда это может быть сработано путем построения массива результатов и утверждения значения массива.
В случае, о котором вы спрашиваете, я не думаю, что множественные утверждения являются проблемой, но я вижу что-то еще, что кажется проблемой для меня. Похоже, ваша спецификация может быть слишком сложной.
Я думаю, что вы пытаетесь утверждать поведение любой вещи james
, но тест также зависит от поведения si_title
, чтобы рассказать нам, что с ним сделано (в порядке от его возможного значения #status
). Вместо этого я бы сделал si_title
test-double и использовал #should_receive
, чтобы напрямую указать сообщения, которые он должен ожидать.
Ответ 4
Я думаю, что Фредерик Чунг дал очень хороший ответ (+1), особенно почему, но я также хотел бы дать сравнительный бит кода, чтобы вы могли посмотреть, какие использует its
, lets
, before
и context
:
context "Given a si_title" do
let(:james) { James.new } # or whatever
before do
james.claim(si_title)
james.release(si_title)
end
context "That is valid" do
let(:si_title) { Si_title.new } # or whatever
describe "James' ideas" do
subject { james.ideas }
its(:size) { should == 0 }
its(:whatever) { should == "Whatever" }
end
describe "Si title" do
subject { si_title }
its(:status) { should == "available" }
end
end
context "That is invalid" do
# stuff here
end
end
Я бы даже пошел дальше и сделал ожидаемые значения let
, а затем сделаю примеры shared_example
s, чтобы они могли затем использоваться для проверки различных аспектов (нулевые аргументы, недопустимые аргументы, неправильный объект...), но я считаю, что это намного лучший способ рассказать о ваших намерениях и все же сократить любое повторение. Взяв пример от Фредерика, ответьте:
it 'should return a prime integer' do
result = subject.do_x
result.should be_a(Integer)
result.foo.should be_prime
end
Используя синтаксис RSpec для полного эффекта, вы получите следующее:
let(:result) { 1 }
subject{ result }
its(:do_x) { should be_a(Integer) }
its(:foo) { should be_prime }
Это означает, что вы можете проверить несколько аспектов предмета.