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