Rspec 测试使用工厂和主题创建和重定向

Rspec testing create and redirect with factories and subject

我想让我的测试尽可能干燥,因此,它们看起来像这样:

describe "creating new product" do
    subject { FactoryGirl.create(:product) }

    it "should increase product count by one" do
        expect{ subject }.to change{ Product.count }.by(1)
    end

    it "and then redirect to product's page" do
        expect(subject).to redirect_to(product_path)
    end
end

这是我的工厂:

FactoryGirl.define do
   factory :product do
      sequence(:title) { |n| "Book#{n}" } 
      description "Some crazy wibbles, they are fun"
      image_url "freddie_mercury.jpg"
      price 56.99
   end  
end

这是我的模型

class Product < ActiveRecord::Base
  validates :title, :description, :image_url, presence: true
  validates :price, numericality: {greater_than_or_equal_to: 0.01}
  validates :title, uniqueness: true
  validates :image_url, allow_blank: true, format: {
    with: %r{\.(gif|jpg|png)\Z}i,
    message: 'must be a URL for GIF, JPG or PNG image'
  }
end

有时我的第一次测试通过(当我在工厂内更改名称时),但过了一段时间我得到:

ProductsController creating new product should increase product count by one
 Failure/Error: subject { FactoryGirl.create(:product) }
 ActiveRecord::RecordInvalid:
   Validation failed: Title has already been taken

这有点疯狂,因为我定义了序列(我尝试使用 do...end 块,而不是 'n' 变量 - 我知道这有点傻,但是尽管如此)

那么,第二个测试也失败了:

ProductsController creating new product and then redirect to product's page
 Failure/Error: expect(subject).to redirect_to(product_path)
 ActionController::UrlGenerationError:
   No route matches {:action=>"show", :controller=>"products"} missing required keys: [:id]

我只是不知道该尝试什么。我的一些尝试:

expect(subject).to redirect_to(product_path(assign(:product))
expect(subject).to redirect_to(product_path(assign(:product).id)
expect{ subject }.to redirect_to(product_path(assign(:product))
expect(subject).to redirect_to(product_path(subject))
expect(subject).to redirect_to(product_path(subject.id)
expect(subject).to redirect_to(product_path(response)
expect(response).to redirect_to(product_path(assign(:product))

如果有任何反馈,我将不胜感激,提前致谢!

P.S。 这是rails_helper.rb

ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'

ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|

  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  config.use_transactional_fixtures = true

  config.infer_spec_type_from_file_location!
end

OP 在评论中发布了答案,所以我只是把它移到这里。

    describe "creating new product" do
      before :each do           
        @product = FactoryGirl.attributes_for(:product)         
      end           
    
      it "increases Product count number by one" do
        expect(post :create, product: @product).to change(Product,:count).by(1)
        end
    
      it "redirects to the created product's page" do
        expect(post :create, product: @product).to redirect_to product_path(assigns(:product))
      end
    end