Rspec 测试控制器操作创建逻辑
Rspec testing controller action create logic
我正在尝试找出测试我的控制器的逻辑。正如您在我的控制器中看到的,如果通过 phone 号码找到客户,它应该呈现客户展示页面,如果通过 phone 号码找不到客户,那么它应该呈现创建页面.
我正在使用 rspec 和 factorygirl。
我的想法是通过构建客户来构建测试,并为其分配特定的 ID:999999 和 phone 号码。
然后执行 post:使用相同的 phone 号码为客户创建。那应该有响应 return 作为 customers/id.
虽然我的代码通过了测试,但当我更改 post: create customer phone 号码时,它仍然通过了。我不知道我做错了什么,但它似乎不对。
控制器:
def create
if @customer = Customer.find_by(phone: customer_params[:phone])
redirect_to @customer
else
@customer = Customer.new(customer_params)
if @customer.save
redirect_to @customer, notice: "Customer was successfully saved"
else
render 'new', notice: "Customer was unsuccessfully saved"
end
end
end
控制器规格 #1(通过):
it "redirects to the #show/id path if it is an existing customer" do
customer = build(:customer)
customer[:id] = 999999
customer[:phone] = "999"
post :create, customer: attributes_for(:customer, phone: "999")
expect(response).to redirect_to(:action => :show, :id => assigns(:customer).id)
end
控制器规格 #2(更改了 post:创建客户 phone)(通过):
it "redirects to the #show/id path if it is an existing customer" do
customer = build(:customer)
customer[:id] = 99999
customer[:phone] = "999"
post :create, customer: attributes_for(:customer, phone: "939")
expect(response).to redirect_to(:action => :show, :id => assigns(:customer).id)
end
在这两种情况下,当找到客户或创建新客户时,response
将是 redirect_to
,这就是您的测试通过的原因。请注意,由于您在测试中使用 build
,这不会将客户保存在数据库中,因此您的测试总是创建一个新的 customer
并且 Customer.find_by(phone: customer_params[:phone])
总是评估为 nil
。
测试 create
操作的最佳方法是比较发出请求前后 Customer
实例的计数。这是您可以改进测试的方法。
let(:customer) { FactoryGirl.create(:customer, phone: '999') }
context 'user not found by phone' do
it 'creates a new customer' do
expect{
post :create, customer: attributes_for(:customer, phone: "999")
}.to change(Customer, :count).by 1
end
it 'redirects to the customer path' do
post :create, customer: attributes_for(:customer, phone: "999")
customer = Customer.last
expect(response).to redirect_to(customer)
#this is another differentiator between the case where a customer is
#found and when one is created
expect(flash[:notice).to eq "Customer was successfully saved"
end
end
context 'user not found by phone' do
before(:each) do
#here we create the customer before each test in this context
customer
end
it 'does not create a new customer' do
expect{
post :create, customer: attributes_for(:customer, phone: customer.phone)
}.not_to change(Customer, :count)
end
it 'redirects to the customer path' do
post :create, customer: attributes_for(:customer, phone: customer.phone)
customer = Customer.last
expect(response).to redirect_to(customer)
#this is another differentiator between the case where a customer is
#found and when one is created
expect(flash[:notice).to be_nil
end
end
我正在尝试找出测试我的控制器的逻辑。正如您在我的控制器中看到的,如果通过 phone 号码找到客户,它应该呈现客户展示页面,如果通过 phone 号码找不到客户,那么它应该呈现创建页面.
我正在使用 rspec 和 factorygirl。
我的想法是通过构建客户来构建测试,并为其分配特定的 ID:999999 和 phone 号码。
然后执行 post:使用相同的 phone 号码为客户创建。那应该有响应 return 作为 customers/id.
虽然我的代码通过了测试,但当我更改 post: create customer phone 号码时,它仍然通过了。我不知道我做错了什么,但它似乎不对。
控制器:
def create
if @customer = Customer.find_by(phone: customer_params[:phone])
redirect_to @customer
else
@customer = Customer.new(customer_params)
if @customer.save
redirect_to @customer, notice: "Customer was successfully saved"
else
render 'new', notice: "Customer was unsuccessfully saved"
end
end
end
控制器规格 #1(通过):
it "redirects to the #show/id path if it is an existing customer" do
customer = build(:customer)
customer[:id] = 999999
customer[:phone] = "999"
post :create, customer: attributes_for(:customer, phone: "999")
expect(response).to redirect_to(:action => :show, :id => assigns(:customer).id)
end
控制器规格 #2(更改了 post:创建客户 phone)(通过):
it "redirects to the #show/id path if it is an existing customer" do
customer = build(:customer)
customer[:id] = 99999
customer[:phone] = "999"
post :create, customer: attributes_for(:customer, phone: "939")
expect(response).to redirect_to(:action => :show, :id => assigns(:customer).id)
end
在这两种情况下,当找到客户或创建新客户时,response
将是 redirect_to
,这就是您的测试通过的原因。请注意,由于您在测试中使用 build
,这不会将客户保存在数据库中,因此您的测试总是创建一个新的 customer
并且 Customer.find_by(phone: customer_params[:phone])
总是评估为 nil
。
测试 create
操作的最佳方法是比较发出请求前后 Customer
实例的计数。这是您可以改进测试的方法。
let(:customer) { FactoryGirl.create(:customer, phone: '999') }
context 'user not found by phone' do
it 'creates a new customer' do
expect{
post :create, customer: attributes_for(:customer, phone: "999")
}.to change(Customer, :count).by 1
end
it 'redirects to the customer path' do
post :create, customer: attributes_for(:customer, phone: "999")
customer = Customer.last
expect(response).to redirect_to(customer)
#this is another differentiator between the case where a customer is
#found and when one is created
expect(flash[:notice).to eq "Customer was successfully saved"
end
end
context 'user not found by phone' do
before(:each) do
#here we create the customer before each test in this context
customer
end
it 'does not create a new customer' do
expect{
post :create, customer: attributes_for(:customer, phone: customer.phone)
}.not_to change(Customer, :count)
end
it 'redirects to the customer path' do
post :create, customer: attributes_for(:customer, phone: customer.phone)
customer = Customer.last
expect(response).to redirect_to(customer)
#this is another differentiator between the case where a customer is
#found and when one is created
expect(flash[:notice).to be_nil
end
end