RSpec:如何使用Expect与尚不存在的资源一起接收?

mxg2im7a  于 2022-09-21  发布在  Ruby
关注(0)|答案(3)|浏览(174)

在通过POST请求调用的操作中,我创建了一个名为RequestOffer的资源,并使用创建的资源作为参数发送了一封包含ActionMailer的电子邮件:

@request_offer = RequestOffer.new(request_offer_params)
if @request_offer.save
    RequestOfferMailer.email_team(@request_offer).deliver_later
end

当我的控制器规范时,我想测试我的RequestOfferMailer是使用带有资源@request_offer作为参数的方法email_team调用的。

当我想使用expect(XXX).to receive(YYY).with(ZZZ)时,我发现的唯一方法是在发出POST请求之前声明我的期望。但是,ZZZ是由这个POST请求创建的,因此我无法在此之前设置我的期望。


# Set expectation first

message_delivery = instance_double(ActionMailer::MessageDelivery)

# ZZZ used in .with() does not exist yet, so it won't work

expect(RequestOfferMailer).to receive(:email_team).with(ZZZ).and_return(message_delivery)
expect(message_delivery).to receive(:deliver_later)

# Make POST request that will create ZZZ

post :create, params

你知道怎么解决这个问题吗?

vuktfyat

vuktfyat1#

如果这是一个功能测试,那么我会将控制器测试从数据库中分离出来。您可以使用instance_doubles和let语句来执行此操作。下面是一个示例,您可以根据自己的目的进行扩展

describe '/request_offers [POST]' do
  let(:request_offer) { instance_double(RequestOffer, save: true) }

  before do
    allow(RequestOffer).to receive(:new).
      with(...params...).
      and_return(request_offer)
  end

  it 'should instantiate a RequestOffer with the params' do
    expect(RequestOffer).to receive(:new).
      with(...params...).
      and_return(request_offer)
    post '/request_offers', {...}
  end

  it 'should email the request offer via RequestOfferMailer' do
    mailer = instance_double(ActionMailer::MessageDelivery)

    expect(RequestOfferMailer).to receive(:email_team).
      with(request_offer).and_return(mailer)

    post '/request_offers', {...}
  end
end

关键是使用‘let’声明一个与您打算创建的模型相同的示例。通过设置对类的期望,您可以将示例Double注入到测试中,并与数据库隔离。请注意,BEFORE块中的“Allow”调用是为了服务于设置对邮件程序对象的期望的稍后规范;第一个测试中的“Expect”调用仍将能够对该调用进行Assert。

hlswsv35

hlswsv352#

确保参数是RequestOffer的示例就足够了吗?然后,您可以使用instance_of匹配器。例如:

expect(RequestOfferMailer).to receive(:email_team).with(instance_of(RequestOffer)).and_return(message_delivery)

我在RSpec 3.0文档中找到了此选项:https://relishapp.com/rspec/rspec-mocks/v/3-0/docs/setting-constraints/matching-arguments

ujv3wf0j

ujv3wf0j3#

with方法的最后一个参数是一个块。你可以在那里打开争论,做任何你想做的事情。

expect(RequestOfferMailer)
  .to receive(:email_team)
  .with(instance_of(RequestOffer)) do |request_offer|
    expect(request_offer.total).to eq(100) # As one example of what you can to in this block 
  end.and_return(message_delivery)

如果您甚至不确定期望的对象类型,也可以将instance_of匹配器设置为anything

相关问题