Несколько операторов должны в одном rspec это предложение - плохая идея? - программирование
Подтвердить что ты не робот

Несколько операторов должны в одном 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, но кажется глупым сделать целый тест, чтобы убедиться, что статус заголовка изменился (одна и та же функция выполняет обе вещи в моем коде).

4b9b3361

Ответ 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 }

Это означает, что вы можете проверить несколько аспектов предмета.