英文:
Testing Rails model method with rspec
问题
我对于为什么这个测试不起作用感到困惑。只有在我给桩方法 `bar` 添加一个返回值时,它才起作用。然而,预期并不希望有一个返回值,所以我只想测试 `foo` 方法内部是否调用了 `bar`。
```ruby
class Event < ApplicationRecord
def foo
bar
end
end
这个测试不起作用。
describe Event, type: :model do
it '调用 bar' do
event = create(:event)
allow(event).to receive(:bar)
expect(event.foo).to receive(:bar)
end
end
错误信息:
Failure/Error: expect(event.foo).to receive(:bar)
(nil).bar(*(any args))
期望: 任意参数出现1次
收到: 任意参数未出现
当我修改测试以添加一个返回值时,测试就起作用了。
describe Event, type: :model do
it '调用 bar' do
event = create(:event)
allow(event).to receive(:bar).and_return(true)
expect(event.foo).to eq(true)
end
end
<details>
<summary>英文:</summary>
I'm confused as to why this test isn't working. It only works when I add a return value to the stubbed `bar` method. However, it is not expected to have a return value, so I only want to test `bar` is called within `foo`.
class Event < ApplicationRecord
def foo
bar
end
end
This test does not work.
describe Event, type: :model do
it 'calls bar' do
event = create(:event)
allow(event).to receive(:bar)
expect(event.foo).to receive(:bar)
end
end
Error message:
Failure/Error: expect(event.foo).to receive(:bar)
(nil).bar(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
When I change the test to add a return value the test works.
describe Event, type: :model do
it 'calls bar' do
event = create(:event)
allow(event).to receive(:bar).and_return(true)
expect(event.foo).to eq(true)
end
end
</details>
# 答案1
**得分**: 1
```plaintext
在这张图片中有很多问题。
让我们从方法开始:
class Event < ApplicationRecord
def foo
bar
end
end
当你调用 `Event.new.foo` 时,你在 `self` 上调用 `#bar`,它是 Event 的实例,而不是方法 `foo`。
如果你做 `expect(event.foo).to receive(:bar)`,你是在方法的返回值上设置期望,这当然不起作用。
如果你想测试调用 foo 是否会调用 bar,你可以在之前设置期望使用 `expect(obj).to recieve :method_name`:
```lang-ruby
describe Event, type: :model do
it 'calls bar' do
event = create(:event)
expect(event).to receive(:bar)
event.foo
end
end
请注意,除非调用了预期的方法,否则示例将失败。
或者,如果你更喜欢安排、行动、断言模式,你可以使用间谍:
describe Event, type: :model do
it 'calls bar' do
# 安排
event = create(:event)
allow(event).to receive(:bar)
# 行动
event.foo
# 断言
expect(foo).to have_recieved(:bar)
end
end
<details>
<summary>英文:</summary>
There is a lot of things wrong in this picture.
Lets start with the method:
class Event < ApplicationRecord
def foo
bar
end
end
When you call `Event.new.foo` you're calling `#bar` on `self` which is the instance of Event. Not on the method `foo`.
If you do `expect(event.foo).to receive(:bar)` you're setting the expectation on the return value of the method which of course doesn't work.
If you want to test that calling foo calls bar you can use `expect(obj).to recieve :method_name` if you want to set the expectation before hand:
````lang-ruby
describe Event, type: :model do
it 'calls bar' do
event = create(:event)
expect(event).to receive(:bar)
event.foo
end
end
Note that you don't have to use allow(event).to receive(:bar)
unless you want to stub the method. expect(event).to receive(:bar)
wraps the method so that RSpec can track the calls to the method.
The example will fail unless the expected method is called.
Or you can use a spy if you prefer the arrage, act, assert pattern:
describe Event, type: :model do
it 'calls bar' do
# arrange
event = create(:event)
allow(event).to receive(:bar)
# act
event.foo
# assert
expect(foo).to have_recieved(:bar)
end
end
答案2
得分: -1
发表问题后找到答案:
describe Event, type: :model do
it '调用 bar' do
event = create(:event)
允许(event).接收(:bar)
期望(event).接收(:bar)
event.foo
end
end
英文:
Found the answer after posting my question:
describe Event, type: :model do
it 'calls bar' do
event = create(:event)
allow(event).to receive(:bar)
expect(event).to receive(:bar)
event.foo
end
end
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论