Rspec控制器测试失败,#create 与关联



我有一个属于用户的客户模型,我的 post#create 控制器测试成功。但是我有一个同时属于用户和计划的订阅模型,但它失败了(我使用的是 rails 5.1.2(。

这是我的规格:

#rspec/controllers/checkout/subscriptions_controller_spec.rb
require 'rails_helper'
RSpec.describe Checkout::SubscriptionsController, type: :controller do
describe 'POST #create' do
let!(:user) { FactoryGirl.create(:user) }
before do
sign_in user
end
context 'with valid attributes' do
it 'creates a new subscription' do
expect { post :create, params: { subscription: FactoryGirl.attributes_for(:subscription) } }.to change(Subscription, :count).by(1)
end
end
end
end

订阅控制器:

# app/controllers/checkout/subscriptions_controller.rb
module Checkout
class SubscriptionsController < Checkout::CheckoutController
before_action :set_subscription, only: %i[edit update destroy]
before_action :set_options
def create
@subscription = Subscription.new(subscription_params)
@subscription.user_id = current_user.id
if @subscription.valid?
respond_to do |format|
if @subscription.save
# some code, excluded for brevity
end
end
else
respond_to do |format|
format.html { render :new }
format.json { render json: @subscription.errors, status: :unprocessable_entity }
end
end
end
private
def set_subscription
@subscription = Subscription.find(params[:id])
end
def set_options
@categories = Category.where(active: true)
@plans = Plan.where(active: true)
end
def subscription_params
params.require(:subscription).permit(:user_id, :plan_id, :first_name, :last_name, :address, :address_2, :city, :state, :postal_code, :email, :price)
end
end
end

订阅模式 -

# app/models/subscription.rb
class Subscription < ApplicationRecord
belongs_to :user
belongs_to :plan
has_many :shipments
validates :first_name, :last_name, :address, :city, :state, :postal_code, :plan_id, presence: true
before_create :set_price
before_update :set_price
before_create :set_dates
before_update :set_dates
def set_dates
# some code, excluded for brevity
end
def set_price
# some code, excluded for brevity
end
end

我也使用一些FactoryGirl工厂作为我的模型。

# spec/factories/subscriptions.rb
FactoryGirl.define do
factory :subscription do
first_name Faker::Name.first_name
last_name Faker::Name.last_name
address Faker::Address.street_address
city Faker::Address.city
state Faker::Address.state_abbr
postal_code Faker::Address.zip
plan
user
end
end
# spec/factories/plans.rb
FactoryGirl.define do
factory :plan do
name 'Nine Month Plan'
description 'Nine Month Plan description'
price 225.00
active true
starts_on Date.new(2017, 9, 1)
expires_on Date.new(2018, 5, 15)
monthly_duration 9
prep_days_required 5
category
end
end
# spec/factories/user.rb
FactoryGirl.define do
factory :user do
name Faker::Name.name
email Faker::Internet.email
password 'Abcdef10'
end
end

当我查看日志时,我注意到在运行规范和创建订阅时未填充用户和计划,这一定是它失败的原因,因为计划是必需的。但是我不知道如何解决这个问题。有什么想法吗?提前谢谢。

问题是,根据模型定义,您只能创建与现有Plan关联的Subscription

class Subscription < ApplicationRecord
belongs_to :plan
validates :plan_id, presence: true
end

您可以通过在rspec测试中设置断点并检查response.body来调试此问题;或者类似地通过在SubscriptionsController#create中设置断点并检查@subscription.errors来调试此问题。无论哪种方式,您都应该看到plan_id不存在的错误(因此@subscription没有保存(。


此问题源于以下事实:FactoryGirl#attributes_for不包含关联的模型 ID。(这个问题实际上在项目中已经多次提出,并进行了详细讨论。

您只需在测试的请求有效负载中显式传递plan_id,即可使其通过:

it 'creates a new subscription' do
expect do
post(
:create,
params: {
subscription: FactoryGirl.attributes_for(:subscription).merge(post_id: 123)
}
end.to change(Subscription, :count).by(1)
end

但是,此解决方案有些艰巨且容易出错。我建议的一个更通用的替代方案是定义以下规范帮助程序方法:

def build_attributes(*args)
FactoryGirl.build(*args).attributes.delete_if do |k, v| 
["id", "created_at", "updated_at"].include?(k)
end
end

这利用了build(:subscription).attributes确实包含外键的事实,因为它引用了关联。

然后,您可以按如下方式编写测试:

it 'creates a new subscription' do
expect do
post(
:create,
params: {
subscription: build_attributes(:subscription)
}
)
end.to change(Subscription, :count).by(1)
end

请注意,此测试仍然有点不现实,因为数据库中实际上并不存在Post!目前,这可能没问题。但将来,您可能会发现SubscriptionController#create操作实际上需要查找关联的Post作为逻辑的一部分。

在这种情况下,您需要在测试中显式创建Post

let!(:post) { create :post }
let(:subscription) { build :subscription, post: post }

。然后将subscription.attributes发送到控制器。

相关内容

最新更新