2016-04-29 13 views
0

Ich schreibe eine RSpec namens Leads Controller-Spezifikation. Darin schreibe ich einen Test für die Erstellung einer Aktion des Lead-Controllers. Jetzt ruft mein Lead-Controller das Projektmodell auf, um ein Objekt (Project) zu erstellen, das auch das Kontaktobjekt erstellt und es dem Projekt zuweist. Aber wenn ich versuche, zu testen, ob mein Projektmodell ein Kontaktobjekt erstellt oder nicht, werden die Tests fehlgeschlagen. Ich weiß nicht, warum mein Kontaktobjekt nicht erstellt bekommen :(Ich kann keine Beziehung zwischen zwei Objekten in Rspec herstellen

Mein leads_controller_spec.rb

describe "POST #create" do 
    it "should create a contact too" do 
     my_lead = Fabricate(:project, id: Faker::Number.number(10)) 
     expect{ 
     post :create, project: my_lead.attributes 
     }.to change(Contact, :count).by(1) 
    end 
    it "should be equal to last created contact" do 
     my_lead = Fabricate(:project, id: Faker::Number.number(10)) 
     post :create, project: my_lead.attributes 
     expect(Project.last.contact).to eq(Contact.last) 
    end 
    end 

leads_controller.rb

def create 
    if @lead = Project.add_new_lead(lead_params) 
     @lead.create_activity :create_new_lead, owner: current_user 
     puts "My lead in create action: #{@lead.inspect}" 
    else 
     respond_to do |format| 
     format.html { redirect_to :back, :alert => "Email is already Taken"} 
     end 
    end 
     respond_to do |format| 
     format.html { redirect_to leads_path } 
     end 
    end 

Project.rb

def add_new_lead(inputs, data = {}) 
     if !Contact.where(email: inputs[:email]).present? 
     contact = Contact.create(phone: inputs[:phone], email: inputs[:email], fullname: inputs[:fullname]) 
     project = Project.create(name: inputs[:fullname], flat_status: inputs[:flat_status], flat_type: inputs[:flat_type], flat_area: inputs[:area], location: inputs[:locality], address: inputs[:site_address], customer_type: inputs[:customer_type]) 
     project.contact = contact 
     project.save 

     project 

     else 
     return nil 
     end 
    end 

contact_fabricator.rb

require 'faker' 
Fabricator(:contact) do 
email { "email_#{Kernel.rand(1..30000)}@prestotest.com" } 
fullname "project#{Kernel.rand(1..30000)}" 
address "address#{Kernel.rand(1..30000)}" 

end 

project_fabricator.rb

require 'faker' 
Fabricator(:project) do 

    contact 
end 

contact.rb

field :phone,    type: String   
    field :email,    type: String 
    field :fullname,   type: String 
    field :status,   type: String,  default: "DEFAULT" 
    field :address,    type: String 
    field :new_address,  type: String 
    field :other_data,  type: Hash,   default: {} 

    validates_presence_of :email 
    validates_uniqueness_of :email, :message => "Email already taken" 
+0

Fehlermeldung: erwartet #count haben um 1 veränderte, wurde aber von 0 – user191990

+0

geändert Ist es möglich, dass Ihr Test keinen neuen 'Kontakt erstellt hat 'weil ein passender Kontakt bereits in der Datenbank vorhanden war oder weil eine Validierung fehlgeschlagen ist? Löschen Sie Ihre Datenbank zwischen zwei Läufen Ihrer Testsuite? Haben Sie eine Validierung für Ihr 'Contact'-Modell? – spickermann

+0

Ja spickermann Ich habe Validierungen für Kontakt-Modell, wie Sie die letzten zwei Zeilen der Contact.rb-Datei sehen können. Aber wenn ich die Validierungen entferne, werden die Tests grün, aber ich brauche trotzdem eine Validierung. – user191990

Antwort

0

Sie die Fabriken in der Spec falsch verwenden. Sie möchten Fabricate.attributes_for(:project) verwenden, anstatt einen Datensatz zu erstellen und dessen Attribute zu übernehmen, da sonst Validierungen der Eindeutigkeit fehlschlagen.

require 'rails_helper' 
describe ProjectsContoller 

    describe "POST #create" do 

    # don't forget to test with invalid input! 
    context "with invalid attributes" do 
     let(:attributes) { { foo: 'bar' } } 
     it "does not create a project" do 
     expect do 
      post :create, attributes 
     end.to_not change(Project, :count) 
     end 
    end 

    context "with valid attributes" do 
     let(:attributes) { Fabricate.attributes_for(:project) } 
     it "creates a project" do 
     expect do 
      post :create, attributes 
     end.to change(Project, :count).by(+1) 
     end 
    end 
    end 
end 

Wenn es um den Rest Ihres Controller kommt sein sollten Sie sehr wahrscheinlich mit nested attributes statt, da Sie nicht der Fall sind Handling, wo die Validierung der Kontakt ausfällt. Sie verwenden auch Contact.create, wenn Sie Contact.new verwenden sollten.

Beachten Sie, dass dies ein ziemlich fortgeschrittenes Thema ist und Sie vielleicht zuerst die Grundlagen lernen und später noch einmal lernen möchten.

class Project < ActiveRecord::Base 
    belongs_to :contact 
    accepts_nested_attributes_for :contact 
    validates_associated :contact 
end 

class Contact < ActiveRecord::Base 
    has_many :projects 
end 

class ProjectsController < ApplicationController 
    def new 
    @project = Project.new 
    end 

    def create 
    @project = Project.new(project_params) 

    if @project.save 
     format.html { render :new } # don't redirect! 
    else 
     format.html { redirect_to leads_path } 
    end 
    end 

    private 

    def project_params 
     params.require(:project).permit(:foo, :bar, contact_attributes: [:email, :name, :stuff, :more_stuff]) 
    end 
end 

<%= form_for(@project) do |f| %> 

    <%= f.text_field :foo %> 

    # These are the attributes for the contact 
    <%= fields_for :contact do |pf| %> 
    <%= pf.text_field :email %> 
    <% end %> 
<% end %> 
Verwandte Themen