Проверка макетов rspec до окончания теста - PullRequest
1 голос
/ 27 июня 2019

Похоже, что стандартный способ использовать mocks rspec в тестовом примере - это сделать что-то вроде этого:

class MyTest
  def setup
    super
    ::RSpec::Mocks.setup(self)
  end

  def teardown
    super
    begin
      ::RSpec::Mocks.verify
    ensure
      ::RSpec::Mocks.teardown
    end
  end

  test "something"
    foo = MyFoo.new
    expect(foo).to receive(:bar).and_return(42)
    ret = SomeClass.call_bar(foo)

    assert_equal(42, ret)
  end
end

Это работает хорошо . Но если SomeClass.call_bar использовал возврат foo.bar в качестве возврата и что-то не так с кодом, так что foo.bar никогда не вызывался, то я получаю только сбой из-за строки assert_equal(42, ret). Я не вижу никакой ошибки как:

RSpec::Mocks::MockExpectationError: (foo).bar
    expected: 1 time
    received: 0 times

Если я удалю строку assert_equal(42, ret), то получу ошибку ожидания rspec. Но я хочу проверить обе вещи: foo.bar был назван и , окончательное возвращение было 42. Более важно знать, что foo.bar не вызывали, так как это источник причины, по которой 42 не был не вернулся.

Если я ожидаю что-то вроде: expect(foo).not_to receive(:bar), тогда я получаю эту ошибку ожидания прямо в источнике вызова, а не позже во время разрыва.

Теперь я могу сделать что-то вроде put ::RSpec::Mocks.verify непосредственно перед вызовом assert_equal, но это не так. Я также не уверен, должен ли я убирать издевательства в этот момент или нет.

Есть ли такой синтаксис, как:

  test "something"
    foo = MyFoo.new
    ret = nil

    expect(foo).to receive(:bar).and_return(42).during do
      ret = SomeClass.call_bar(foo)
    end

    assert_equal(42, ret)
  end

Так что проверка происходит сразу после того, как блок перешел на during? Или, может быть, если у вас есть несколько двойных, вы можете сделать что-то вроде:

    expect(dbl1).to receive(:one)
    expect(dbl2).to receive(:two)
    expect(dbl3).to receive(:three)

    verify(dbl1, dbl2, dbl3).during do
      my_code
    end

Ответы [ 3 ]

1 голос
/ 27 июня 2019

Вы ищете rspec spies .

Шпионы - альтернативный тип двойного теста, который поддерживает это шаблон, позволяющий вам ожидать, что сообщение было получено после факта, используя have_received.

Вы создаете частичную двойную комбинацию из foo с помощью allow(...).to receive, а затем можете подтвердить получение сообщения:

test "something"
  foo = MyFoo.new
  allow(foo).to receive(:bar).and_return(42)
  ret = SomeClass.call_bar(foo)
  expect(foo).to have_received(:bar)
  assert_equal(42, ret)
end
1 голос
/ 27 июня 2019

Я считаю, что вам нужно объединить сбои https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/aggregating-failures

При "нормальной" настройке любая ошибка прерывает тест и никакие последующие утверждения не проверяются.

0 голосов
/ 27 июня 2019

Я не думаю, что есть какой-то встроенный способ сделать это, но если вы добавите следующий класс:

class VerifyDuring
  def initialize(test, objects)
    @test = test
    @objects = objects
  end

  def during
    yield
  ensure
    begin
      @objects.each do |object|
        RSpec::Mocks.proxy_for(object).verify
      end
    rescue Exception => e
      @test.flunk e
    end
  end
end

И следующий метод в ваш тестовый класс:

  def verify(*objects)
    VerifyDuring.new(self, objects)
  end

Вы можете сделать это:

    verify(dbl1, dbl2, dbl3).during do
      my_code
    end
...