2013-07-29 10 views
6

Kann ich wissen, wie stub Methode, die in der Controller Create-Methode ist? Ich muss die Spezifikation dafür schreiben, aber ich habe diese Fehler. Ich muss überprüfen, dass die create-Methode im Controller die validate_fbid-Methode ausführen muss, bevor ein neuer Firmendatensatz im Modell erstellt wird.Rspec: Stub-Methode, die in der Steuerung ist

Fehler:

1) Companies new company create with valid information#validate_fbid should have correct parameters and return value 
Failure/Error: CompaniesController.create.should_receive(:validates_fbid).with(company) 
NoMethodError: 
    undefined method `create' for CompaniesController:Class 
# ./spec/requests/companies_spec.rb:38:in `block (5 levels) in <top (required)>' 

    2) Companies new company create with valid information#validate_fbid should fbid validation passed 
Failure/Error: CompaniesController.create.stub(:validates_fbid).and_return('companyid') 
NoMethodError: 
    undefined method `create' for CompaniesController:Class 
# ./spec/requests/companies_spec.rb:43:in `block (5 levels) in <top (required)>' 

CompaniesController

def create 
company = Company.new(params[:company]) 
verifyfbid = validate_fbid(company) 

if verifyfbid != false 
    if company.fbid.downcase == verifyfbid.downcase 
     if company.save 
      @message = "New company created." 
      redirect_to root_path 
     else 
      @message = "Company create attempt failed. Please try again." 
      render 'new' 
     end 
    else 
     @message = "Company create attempt failed. Invalid facebook id." 
     render 'new' 
    end 
else 
    @message = "Company create attempt failed. No such facebook id." 
    render 'new'    
    end    
end 

    private 
    def validate_fbid(company) 
    uri = URI("http://graph.facebook.com/" + company.fbid) 
    data = Net::HTTP.get(uri) 
    username = JSON.parse(data)['username']  
    if username.nil? 
    return false 
    else 
    "#{username}" 
    end 
end 

Anfragen/companies_spec.rb

context "#validate_fbid" do    
     #validate fbid 
     let(:company){ Company.new(name:'Example Company', url: 'www.company.com', fbid: 'companyid', desc: 'Company desc')} 

     it "should have correct parameters and return value" do 
      CompaniesController.create.should_receive(:validates_fbid).with(company) 
           .and_return('companyid') 
     end 

     it "should fbid validation passed" do    
      CompaniesController.create.stub(:validates_fbid).and_return('companyid') 
      company.fbid.should_not be_nil 
      company.fbid.should == 'companyid' 
      company.save 
      expect { click_button submit }.to change(Company, :count).by(1) 
     end            
    end  

Antwort

15

Sie wollen nicht die Methode Stummel, wenn es das Thema Ihres ist Testfall

, wenn Sie die Aktion in der Steuerung erstellen testen, können Sie Stummel "validate_fbid"

describe "post create" do 
    ... 
    CompaniesController.any_instance.stub(:validates_fbid).and_return('companyid') 
    ... 
end 

Hoffe, es hilft.

+10

'allow_any_instance_of (CompaniesController) .TO erhalten (: validates_fbid).and_return ('companyid') 'für Rspec3 – ryan2johnson9

5

Wenn Code schwer zu testen ist, ist es normalerweise, weil es komplex ist.

Sie diesen Code auf diese Weise umgestalten sollte:

  • bewegen die Prüfungslogik in neue ‚Serviceklasse‘, die auf Facebook eine einzige Verantwortung von Unternehmen Überprüfung hat
  • diese unabhängige Überprüfung Funktionalität der Web-Schicht machen und viel einfacher testen
  • make-Spezifikation für Service-Klasse, die diesen Code in Isolation testen (keine Controller)
  • Bereinigungs die Steuerung der Logik - Sie don‘ t wollen in Ihrem Controller-Logik haben (Daumenregel: eine Ebene der Verschachtelung max)
  • Spezifikation für Steuerung einfacher als auch sein

Der Code-Controller wie folgt aussehen kann:

def create 
    company = Company.new(params[:company]) 
    verified = FbCompanyVerifier.new.verify(company) 

    if verified and company.save 
    # success logic 
    else 
    # fail logic 
    end 
end 
+0

Hallo, danke für die Antwort. Bedeutet das, dass ich eine Klasse FbCompanyVerifier erstellen muss, die auch eine "neue" Methode und eine "verify" -Methode hat? Ich nehme an, ich bin nicht erlaubt, eine Klasse in der Controller-Seite zu erstellen, welchen Ordner ich "FbCompanyVerifier" erstellen sollte? Danke für die Klarstellung. Ich bin sehr neu dazu. –

+0

Korrekt - eine vollständige Klasse mit der Instanzmethode 'verify' und Sie können die 'new' (initialize) -Methode überspringen, wenn sie nichts bewirkt. Normalerweise ist dies eine Best Practice, also arbeiten Sie mit erstklassigen Objekten/einfachen Rubinobjekten. (Einige verwenden Klassen mit Klassenmethoden, die ihre eigenen Pros & Contras haben). Da diese Klasse von Ihrem Modellunternehmen abhängig ist, sollten Sie es irgendwo in den App-Ordner 'app/services' einfügen. Sie können dort kleine einfache Verantwortlichkeitsklassen einfügen, die eine oder zwei Methoden enthalten und unabhängig von der Webschicht sind. – jurglic

+0

Sie können auch code_climate blog post, die ähnliche Refactoring - Extrahieren von Logik-Code in neue Klasse mit einfacher Verantwortung beschreibt schreiben, einfache Spezifikation schreiben und dann als PORO (plain-old-ruby-object) im Code verwenden ... : http://blog.codeclimate.com/blog/2013/07/23/testing-code-in-rails-initializer/ – jurglic

1

Wenn Sie Controller testen, können Sie Controller direkt zugreifen:

controller.stub(:message) { 'this is the value to return' } 
+0

Diese Antwort funktioniert für mich, denn wenn ich die Methode stub, weiß ich, dass es ein Argument braucht, aber ich weiß nicht, was das Argument ist. Ich möchte nur das Argument weitergeben, also verwende ich einen Block mit einem Argument, um die Methode zu überschreiben (stub). – Volte