RSpec - 无法模拟 ActiveRecord 模型 class

RSpec - Can't mock ActiveRecord model class

试图在 RSpec 单元测试中模拟 ActiveRecord 模型 class。这里我总结一下。

RSpec 测试

it 'calls create method' do
  response_code = post @url, params: { id: @id }
  expect(response_code).to eql(200)

  allow(MyModel).to receive(:create)

  expect(MyModel).to receive(:create)
end

控制器方法

控制器入口点。

def controller_method
  other_model_method
  #...
  render json: #...
end

调用MyModel的其他模型

Class OtherModel < ActiveRecord
  #...

  def other_model_method
    MyModel.create(attr: value)
  end
end

运行 我得到的测试:

(MyModel(id: integer).create(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

我是 Rails 和 Ruby 的新手。我在另一个 post 中看到的这对 allow(MyModel)/expect(MyModel) 但对我不起作用。我做错了什么?

你的模拟期望应该在代码调用它们之前在测试中发生,所以

it 'calls create method' do
   expect(MyModel).to receive(:create)

   response_code = post @url, params: { id: @id }
   expect(response_code).to eql(200)
end

首先,最好在触发操作之前进行 allow 调用。然后您需要使用过去式匹配器来检查您的模拟是否被调用。

养成这种习惯的好处是,您在测试中使用相同的风格,您只需要模拟一些东西,就像您关心针对这些模拟设定期望时一样。

像这样:

it 'calls create method' do
  allow(MyModel).to receive(:create)

  response_code = post @url, params: { id: @id }

  expect(response_code).to eq(200)
  expect(MyModel).to have_received(:create).with(some: value)
end

您可以将 some: value 替换为您期望调用模拟的任何内容。

如果您在同一规范的大量测试中执行此操作,您可以将 allow 调用转移到 before 块。像这样:

before do
  allow(MyModel).to receive(:create)
end

it 'calls create method' do
  response_code = post @url, params: { id: @id }

  expect(response_code).to eq(200)
  expect(MyModel).to have_received(:create).with(some: value)
end