Ошибка сохранения объекта при проверке данных спецификации

#ruby-on-rails #ruby-on-rails-3.1 #rspec2

#ruby-on-rails #ruby-on-rails-3.1 #rspec2

Вопрос:

Вот неудачный код спецификации для создания в контроллере клиента:

 describe CustomersController do

  before(:each) do
    #the following recognizes that there is a before filter without execution of it.
    controller.should_receive(:require_signin)
    controller.should_receive(:require_employee)
  end

  render_views

    describe "'create' successful" do
      before(:each) do
        category = Factory(:category)
        sales = Factory(:user)      
        @customer = Factory.attributes_for(:customer, :category1_id => category.id, :sales_id => sales.id)
        session[:sales] =  true
        session[:user_id] = sales.id
        session[:user_name] = sales.name
        session[:page_step] = 1
        session['page1'] = customers_path
      end

      it "should create one customer record" do
        lambda do
          post 'create', @customer         
        end.should change(Customer, :count).by(1)
      end

      it "should redirect to customers path" do
        put 'create', @customer
        flash[:notice].should_not be_nil
        response.should redirect_to(customers_path)
      end
    end
 end
  

У клиента есть как идентификатор продажи, так и идентификатор категории, которые принадлежат таблице user и category соответственно.

Вот ошибка сбоя спецификации:

   1) CustomersController GET customer page 'create' successful should create one customer record
     Failure/Error: lambda do
       count should have been changed by 1, but was changed by 0
     # ./spec/controllers/customers_controller_spec.rb:37:in `block (4 levels) in <top (required)>'

  2) CustomersController GET customer page 'create' successful should redirect to customers path
     Failure/Error: flash[:notice].should_not be_nil
       expected: not nil
            got: nil
     # ./spec/controllers/customers_controller_spec.rb:44:in `block (4 levels) in <top (required)>'
  

Вот код приложения для создания в контроллере клиента:

   def create

    if session[:sales]
      @customer = Customer.new(params[:customer], :as => :roles_new_update)
      @customer.sales_id = session[:user_id]
      if @customer.save 
        @message = "New customer #{params[:name]} was created. Please check it out"
        @subject = "New customer #{params[:name]} was created BY {#session[:user_name]}"
        UserMailer.notify_tl_dh_ch_ceo(@message, @subject, session[:user_id])
        redirect_to session[('page'   session[:page_step].to_s).to_sym], :notice => 'Customer was created successfaully!'          
      else
        render 'new', :notice => 'Customer was not saved!'
      end
    end
  end
  

Вот код в factories.rb:

 Factory.define :customer do |c|
  c.name                    "test customer"
  c.short_name              "test"   
  c.email                   "t@acom.com"
  c.phone                   "12345678"
  c.cell                    "1234567890"
  c.active                  1
  c.category1_id            2
  c.sales_id                1
  c.address                 "1276 S. Highland Ave, Lombard, IL 67034"
  c.contact                 "Jun C"

end

Factory.define :category do |c|
  c.name                   "category name"
  c.description            "test category"
  c.active                 true
end

Factory.define :user do |user|

  user.name                  "Test User"
  user.email                 "test@test.com"
  user.password              "password1"
  user.password_confirmation "password1"
  user.status                "active"
  user.user_type             "employee"

end
  

Похоже, что ошибка была вызвана тем, что @customer.save вернул false, а код для «if @customer.save» не был выполнен. Таким образом, проблема может быть в @customer, сгенерированном Factory, что мне кажется хорошим. Код выполняется без каких-либо проблем при сохранении клиента.

Есть предложения? Спасибо.

Ответ №1:

Я бы разбил это на два конкретных теста. Прямо сейчас вы не уверены в двух вещах:

  1. клиенту говорят сохранить себя?
  2. Существует ли проверка, которая препятствует сохранению клиента?

Самый быстрый путь — изменить @customer.save на @customer.save! и посмотрите, есть ли какие-либо исключения (это произойдет, если проверка не удалась).

Я рекомендую вам разделить это. Чтобы протестировать # 1, в спецификации контроллера:

 it "should tell the customer to save itself when there is a session[:sales]" do
  session[:sales] = true
  customer_mock = double(:customer)
  customer_mock.should_receive(:sales_id=)
  customer_mock.should_receive(:save).and_return(:true)
  Customer.stub(:new => cutomer_mock)
  post 'create'
end
  

Затем в вашем customer_spec протестируйте:

 it "should be valid with factory specs" do
  customer = Customer.new(Factory.attributes_for(:customer))
  customer.should be_valid
end
  

Комментарии:

1. Я добавил ваш код в спецификацию для контроллера. Вот сообщение об ошибке: 1) CustomersController успешно «создает» страницу клиента, должен сообщить клиенту сохранить себя при сбое / ошибке сеанса [: sales]: Customer.stub(:new => cutomer_mock) Ошибка имени: неопределенная локальная переменная или cutomer_mock' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1::Nested_1:0x43d4d98> # ./spec/controllers/customers_controller_spec.rb:41:in блок методов (4 уровня) в <top (обязательно)>’

2. 2) CustomersController успешно СОЗДАЕТ страницу клиента, которая должна быть действительной при сбое / ошибке заводских спецификаций: customer.should be_valid ожидаемый действительный? чтобы вернуть true, получил false # ./spec/controllers/customers_controller_spec.rb:47:в `блоке (4 уровня) в <top (обязательно)>’

3. В первом примере вы, вероятно, неправильно ввели код. Во-вторых, это доказывает, что проверка мешает вам. Следующие шаги зависят от вас.

4. Видите ли вы какие-либо проблемы с образцами данных, созданными Factory? Я считаю, что есть проблема, но не вижу ее.

5. На самом деле у меня нет возможности судить об этом. Это зависит от ваших заводских определений и от проверки, которую вы определяете для своей модели.

Ответ №2:

 post :create, :customer => @customer
  

решает проблему с выше.