Rspec: ожидайте, что ассоциация получит сообщение - PullRequest
1 голос
/ 11 октября 2019

Я в Rails 6 с Rspec 3.8.0.

У меня есть модель A, которая belongs_to B. И я пытаюсь написать модульный тест с A как subject:

expect(subject.b).to receive(:to_s)
subject.my_fn

Тем не менее, эта спецификация всегда терпит неудачу, говоря, что экземпляр B не получил сообщение, несмотря на то, что я вставил binding.pry в фактический код для запуска и проверил, что a.b.to_s Меня зовут:

class A
  def my_fn
    binding.pry
    b.to_s
  end
end

Я даже пытался:

expect(a).to receive(:b).and_return(b)
expect(b).to receive(:to_s)

И:

expect_any_instance_of(b.class).to receive(:to_s)

И все ожидания от to_s не оправдались. Почему это?

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Это не отображается в вашем коде, но я чувствую, что вы звоните по номеру code до того, как настроите свои ожидания получения. Проще говоря, выполнение кода должно выглядеть следующим образом:

it 'something' do
  expect(subject.b).to receive(:to_s)

  # write code here that would eventually call `a.b.to_s` (as you have said)
  # i.e.
  # `subject.some_method` (assuming `some_method` is your method that calls `a.b.to_s`
  # don't call `subject.some_method` before the `expect` block above.
end
  • Кроме того, на случай, если вы еще не знаете, убедитесь, что это тот же экземпляр объекта, который вы передаете, чтобы ожидать:expect(THE_ARG) ... receive() и объект, который вы тестируете, для вызова. Вы можете проверить, что они одинаковы, если они имеют одинаковые object_id:
it 'something' do
  puts subject.b.object_id
  # => 123456789

  subject.some_method
end

# the class/method you're unit-testing:
class Foo
  def some_method
    # ...
    puts b.object_id
    # => 123456789
    # ^ should also be the same

В противном случае, если это не тот же объект (object_id не совпадает), вам придется использовать либо expect_any_instance_of (который я использую только в крайнем случае, поскольку он потенциально опасен, поскольку он ожидает "любой экземпляр") ... или вы можете заглушить цепочку a.b.to_s объектов в вашем файле спецификации.

Еслитрудно заглушить всю цепочку, но в то же время, избегайте ловушек использования expect_any_instance_of, я использую другой вариант, который я использую, чтобы сбалансировать удобство и точность спецификации:

it 'something' do
  expect_any_instance_of(subject.b.class).to receive(:to_s).once do |b|
    expect(b.id).to eq(subject.b.id)
    # the above just compares the `id` of the records (even if they are different objects in different memory-space)

    # to demonstrate, say I do puts here:
    puts b
    # => #<SomeRecord:0x00005600e7a6f3b8 id:1 ...>
    puts subject.b
    # => #<SomeRecord:0x00005600e4f04138 id:1 ...>
    puts b.id
    # => 1
    puts subject.b.id
    # => 1

    # notice that they are different objects (0x00005600e7a6f3b8 vs 0x00005600e4f04138)
    # but the attribute id is the same (1 == 1)
  end

  subject.some_method
end
0 голосов
/ 11 октября 2019

Кажется, что больше смысла заглушить отношение b. Это будет выглядеть так:

expect(a).to receive(:b).and_return(stub(:b, to_s: 'foo_bar')

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...