2016-04-20 11 views
0

Ich versuche, einen Test-Pass für Code, der bereits implementiert wurde, zu machen. Ich bin neu in Unit Testing und RSpec und für das Leben von mir kann diesen Fehler nicht herausfinden. Im Grunde versuche ich zu überprüfen, dass JSON an den richtigen Endpunkt gesendet wird. Ich denke, ich habe alle Attribute geschaffen, die ich brauchte, aber ich bekomme immer denselben Fehler. Hier ist der Fehler und mein Code. Es hat eindeutig etwas damit zu tun, die Stadt von einem anderen Modelltisch mitzunehmen, aber ich bin mir nicht sicher, warum es sich beschwert?Rspec - Versucht, nil zu verstehen: NilClass Fehler

Hier ist der Test.

require "rails_helper" 

RSpec.describe "/api/retailers" do 

describe "GET /api/retailers" do 
it "Returns JSON for retailers" do 

    location = Location.create!(
     city: "Portland", 
     street_1: "Cherry", 
     state: "Oregon", 
     zip: "49490" 
    ) 

    retailer = Retailer.create!(
    name: "Good Coffee Co.", 
    description: "Hipster Good", 
    image_url: "http://www.example.com/foo_bar.jpg", 
) 

    get "/api/retailers.json" 

    expect(response).to be_success 
    json = JSON.parse(response.body) 

    expect(json["name"]).to eql("Good Coffee Co.") 
    expect(json["description"]).to eql("Hipster Good") 
    expect(json["image_url"]).to eql("http://www.example.com/foo_bar.jpg") 
    expect(json["city"]).to eql(location.city) 
end 
end 
end 

Hier ist meine Fehlermeldung

/api/retailers GET /api/retailers Returns JSON for retailers 
Failure/Error: location.city 

NoMethodError: 
    undefined method `city' for nil:NilClass 
# ./app/models/retailer.rb:8:in `city' 

Hier mein Controller ist

class Api::RetailersController < ApiController 
def index 
    @retailers = Retailer.all 
    render json: @retailers, methods: [:city] 
end 
end 

Hier ist mein Modell

class Retailer < ActiveRecord::Base 
has_one :location 

has_many :retailer_timeslots 
has_many :timeslots, through: :retailer_timeslots 

def city 
location.city 
end 
end 

Jede Hilfe wäre genial. Ich bin wirklich auf dieses Problem gestoßen. Lassen Sie mich wissen falls andere Informationen notwendig sind.

Antwort

1

Ihr Retailer Modell hat eine Beziehung mit location.

Und Sie haben eine city Methode auf ihm auch, die jetzt an diesem location

def city 
    location.city 
end 

suchen ist, das in dem Controller enthalten ist:

render json: @retailers, methods: [:city] 

nun in Ihrem Test, Sie erstellt eine location und retailer:

location = Location.create!(
     city: "Portland", 
     street_1: "Cherry", 
     state: "Oregon", 
     zip: "49490" 
    ) 

    retailer = Retailer.create!(
    name: "Good Coffee Co.", 
    description: "Hipster Good", 
    image_url: "http://www.example.com/foo_bar.jpg", 
) 

Aber diese beiden sind in keiner Weise verwandt.

Also, wenn in Ihrem Test, können Sie eine get Anfrage an die index Aktion des Controllers senden,

get "/api/retailers.json" 

Dieser versucht, die city für den Händler zu erhalten, die die oben beschriebene Methode ist. aber bedenken Sie, dass die Methode versucht, location.city

zu erhalten. Aber Ihre retailer hat keine location, weil es nicht mit ...Also, location hier wird nil

und dann, wenn Sie city auf location nennen (die Null ist), werden Sie city auf nil

Aufruf Dies ist, wo der Fehler kommt:

NoMethodError: 
    undefined method `city' for nil:NilClass 
# ./app/models/retailer.rb:8:in `city' 

Edit (Fix):

den Standort als Händler Standort erstellt Fügen Sie in Ihrem Test als folgen:

location = Location.create!(
    city: "Portland", 
    street_1: "Cherry", 
    state: "Oregon", 
    zip: "49490" 
) 

retailer = Retailer.create!(
    name: "Good Coffee Co.", 
    description: "Hipster Good", 
    image_url: "http://www.example.com/foo_bar.jpg", 
    location: location # Add location as location here. 
) 
+0

ich sehen! ja, Irgendeine Idee, was Sie tun würden, um zu beheben? – Bitwise

+0

der Fix ist wie oben von Max und Rodrigo gezeigt. Ich füge meine Antwort hier als Bearbeitung hinzu. –

1

Die city Methode verwenden, um die Lage von Retailer, die nicht für die Eins gesetzt wurde Sie erstellt.

Um dies zu lösen, weisen nur die location Verein Retailer:

retailer = Retailer.create!(
    name: "Good Coffee Co.", 
    description: "Hipster Good", 
    image_url: "http://www.example.com/foo_bar.jpg", 
    location: location 
) 
1

Sie eigentlich nie den Zusammenhang zwischen Einzelhändler und Standort einrichten. Wenn also aufgerufen wird, ist location gleich null.

Sie können, indem Sie Ihre Methode starten wollen nil graziös zu behandeln, es sei denn Ihre Business-Logik sollte kein Händler ohne Ort ermöglichen:

class Retailer < ActiveRecord::Base 
    has_one :location 

    has_many :retailer_timeslots 
    has_many :timeslots, through: :retailer_timeslots 

    def city 
    location.city if location 
    end 
end 

Eine elegantere Weg ist durch Module#delegate mit:

class Retailer < ActiveRecord::Base 
    has_one :location 

    has_many :retailer_timeslots 
    has_many :timeslots, through: :retailer_timeslots 

    delegate :city, to: :location, allow_nil: true 
end 

Dies sollte die Spezifikation von fehlerhaft zu fehlerhaft ändern.

die Spezifikation beheben Sie eine Beziehung zwischen den beiden Setup benötigen:

location = Location.create!(
    city: "Portland", 
    street_1: "Cherry", 
    state: "Oregon", 
    zip: "49490" 
) 

retailer = Retailer.create!(
    name: "Good Coffee Co.", 
    description: "Hipster Good", 
    image_url: "http://www.example.com/foo_bar.jpg", 
    location: location # !!!!! 
) 
Verwandte Themen