1

我对一些控制器测试有疑问。以下两个都失败了,但我真的不知道为什么。更新和销毁工作正常。

我正在使用 Rails 4.0 和 mongoid。

describe 'POST create' do
context 'with valid attributes' do
  it 'creates a new restaurant' do
    expect {
      post :create, restaurant: FactoryGirl.attributes_for(:random_restaurant)
    }.to change(Restaurant, :count).by(1)
  end

  it 'redirects to the new restaurant' do
    post :create, restaurant: FactoryGirl.attributes_for(:random_restaurant)
    response.should redirect_to Restaurant.last
  end
end

我刚刚添加了从餐厅到地址的关系,更新了我的 factorygirl 固定装置。

这些是我的固定装置:

factory :random_restaurant, parent: :restaurant do |r|
  r.name {Faker::Company.name}
  r.description {Faker::Lorem.sentences}

  after(:build) do |restaurant|
    restaurant.addresses << FactoryGirl.build(:random_address)
  end
end

factory :random_address, parent: :address do |a|
  a.street {Faker::Address.street_address}
  a.zip {Faker::Address.zip_code}
  a.city {Faker::Address.city}
end

控制器后创建方法看起来像这样(仍然默认)

# POST /restaurants
# POST /restaurants.json
def create
  @restaurant = Restaurant.new(restaurant_params)

  respond_to do |format|
    if @restaurant.save
      format.html { redirect_to @restaurant, notice: 'Restaurant was successfully created.' }
      format.json { render action: 'show', status: :created, location: @restaurant }
    else
      format.html { render action: 'new' }
      format.json { render json: @restaurant.errors, status: :unprocessable_entity }
    end
  end
end

错误是:

Failures: 1) RestaurantsController POST create with valid attributes creates a new restaurant
 Failure/Error: expect {
   count should have been changed by 1, but was changed by 0
 # ./spec/controllers/restaurants_controller_spec.rb:39:in `block (4 levels) in <top (required)>'

2) RestaurantsController POST create with valid attributes redirects to the new restaurant
 Failure/Error: response.should redirect_to Restaurant.last
   Expected response to be a <redirect>, but was <200>
 # ./spec/controllers/restaurants_controller_spec.rb:46:in `block (4 levels) in <top (required)>'

Finished in 0.85251 seconds
19 examples, 2 failures

Failed examples:

rspec ./spec/controllers/restaurants_controller_spec.rb:38 # RestaurantsController POST create with valid attributes creates a new restaurant
rspec ./spec/controllers/restaurants_controller_spec.rb:44 # RestaurantsController POST create with valid attributes redirects to the new restaurant

这是一个正在运行的更新测试:

describe 'PUT update' do
before :each do
  @restaurant = FactoryGirl.create(:random_restaurant)
end

context 'with valid attributes' do
  it 'locates the requested @restaurant' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    assigns(:restaurant).should eq(@restaurant)
  end

  it 'changes @restaurants attributes' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    @restaurant.reload
    @restaurant.name.should eq('A Lodge')
    @restaurant.description.should eq('A Bar')
  end

  it 'redirects to @restaurant' do
    put :update, id: @restaurant, restaurant: FactoryGirl.attributes_for(:restaurant)
    response.should redirect_to @restaurant
  end
end

有谁知道,为什么这会失败以及我该如何解决?非常感谢您

更新:你的意思是这样的吗?这是来自 test.log

Processing by RestaurantsController#create as HTML
Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
"description"=>["Quae labore quia officia soluta voluptatibus.", "Et error incidunt beatae laborum a libero officiis.", "Non excepturi dolor vel."], 
"thumbnail"=>"some url", "banner"=>"some url"}}
**Unpermitted parameters: thumbnail, banner**

更新 2

这些测试也有效:

describe Restaurant do
  it 'has a valid factory' do
    FactoryGirl.create(:random_restaurant).should be_valid
  end

  it 'has an invalid factory' do
    FactoryGirl.build(:random_restaurant_with_invalid_address).should_not be_valid
  end

  it 'is invalid without a name' do
    FactoryGirl.build(:random_restaurant, name: nil).should_not be_valid
  end

  it 'is invalid without a description' do
    FactoryGirl.build(:random_restaurant, description: nil).should_not be_valid
  end

  it 'is invalid without an address' do
    FactoryGirl.build(:random_restaurant_with_invalid_address).should_not be_valid
  end

  it 'creates an address when created' do
    FactoryGirl.create(:random_restaurant)
  end
end

更新 3

我的模型:

class Restaurant
  include Mongoid::Document

  has_many :addresses, dependent: :destroy

  validates :name, presence: true
  validates :description, presence: true
  validates :addresses, presence: true

  field :name, type: String
  field :description, type: String
  field :thumbnail, type: String
  field :banner, type: String
end


class Address
  include Mongoid::Document

  belongs_to :restaurant

  validates :street, presence: true
  validates :zip, presence: true
  validates :city, presence: true

  field :street, type: String
  field :zip, type: Integer
  field :city, type: String

  def full_address
    zip_city = [zip, city].join ' '
    [street, zip_city].join ', '
  end
end

更新 4

所以,我发现了这个: 如何在 Rails 4 中使用 attr_accessible?

并更新了我的方法。但仍然无法正常工作:(

def restaurant_params
  params.require(:restaurant).permit(:name, :description, :thumbnail, :banner, addresses_attributes: [ :street, :zip, :city ])
end
4

3 回答 3

2

只需在控制器上放一个 puts @restaurant.errors.full_messages,看起来它没有通过验证

respond_to do |format|
  if @restaurant.save
    format.html { redirect_to @restaurant, notice: 'Restaurant was successfully created.' }
    format.json { render action: 'show', status: :created, location: @restaurant }
  else
    puts @restaurant.errors.full_messages
    format.html { render action: 'new' }
    format.json { render json: @restaurant.errors, status: :unprocessable_entity }
  end
end

不去运行该规范并检查终端上的输出

您还可以添加此规范来测试您的工厂,这样您就可以确保您的工厂正常工作:

it 'creates a valid restaurant from factory girl' do
  rest = FactoryGirl.build :random_restaurant
  rest.should be_valid
end
于 2013-11-01T19:04:39.797 回答
1

所以问题在于使用

FactoryGirl.attributes_for(:random_restaurant)

这不是添加地址属性,并且您的餐厅至少验证了一个属性的存在。查看您问题中的 POSTed 属性:

Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
               "description"=>["Quae labore quia officia soluta voluptatibus.", 
                               "Et error incidunt beatae laborum a libero officiis.", 
                               "Non excepturi dolor vel."], 
               "thumbnail"=>"some url", "banner"=>"some url"}}

这里没有地址信息。当您创建一家新餐厅时,您至少需要一个地址。POSTed 参数应如下所示:

Parameters: {"restaurant"=>{"name"=>"Schneider, Franecki and Tillman", 
               "description"=>["Quae labore quia officia soluta voluptatibus.", 
                               "Et error incidunt beatae laborum a libero officiis.", 
                               "Non excepturi dolor vel."], 
               "thumbnail"=>"some url", "banner"=>"some url",
               "addresses"=>[{"street" => "...", "city => "...", "zip" => "..."}, ...] }}

我建议您为创建案例手动构建属性。如果不出意外,它应该可以帮助您了解控制器如何解析参数

未经许可的参数问题是一个单独的问题,可以在您获得地址参数后解决。

明白了吗?

于 2013-11-01T19:55:36.867 回答
1

首先,感谢大家的帮助。有了你的想法,我得到了解决方案,我现在不使用 factoryGirl。正如@PeterGoldstein 提到的,我使用参数。我犯了一个错误,我使用了地址而不是地址属性。我不知道为什么我必须像我必须的那样使用它,但我会弄清楚的。

这是我现在适合我的解决方案:

expect {
      post :create, restaurant: { name: 'A-Lodge', description: 'descr',
                                    thumbnail: 'this is url to thumbnail', banner: 'this is url to banner',
                                    addresses_attributes: [ { street: 'street', zip: '8888', city: 'city' } ] }
    }.to change(Restaurant, :count).by(1)
于 2013-11-02T00:42:59.037 回答