2014-01-12 7 views
18

Wie kann ich testen, dass eine bestimmte Instanzvariable in meinem my Mailer mit rspec gesetzt ist? zuordnet zurück undefined kommen ..Wie kann ich testen, dass eine Instanzvariable in meinem my Mailer mit rspec gesetzt ist?

require File.dirname(__FILE__) + '/../../spec_helper' 

describe UserMailer do 

    it "should send the member user password to a User" do 
    user = FG.create :user 

    user.create_reset_code 

    mail = UserMailer.reset_notification(user).deliver 

    ActionMailer::Base.deliveries.size.should == 1 

    user.login.should be_present 

    assigns[:person].should == user 
    assigns(:person).should == user #both assigns types fail 
    end 
end 

Der Fehler zurückgegeben:

undefined local variable or method `assigns' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fe2b88e2928> 

Antwort

21

assigns nur für Controller Spezifikationen definiert ist, und das ist über die rspec-Schienen gem getan. Es gibt keinen allgemeinen Mechanismus zum Testen von Instanzvariablen in RSpec, aber Sie können Kernel instance_variable_get verwenden, um auf eine beliebige Instanzvariable zuzugreifen.

Also in Ihrem Fall, wenn object die Objektinstanz, deren variierten Sie bei der Überprüfung interessiert waren, könnten Sie schreiben:

expect(object.instance_variable_get(:@person)).to eql(user) 

Was ahold der UserMailer Instanz bekommen, kann ich sehen keine Möglichkeit, das zu tun. Wenn Sie die method_missing Definition innerhalb von https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb betrachten, wird eine neue Mailer-Instanz immer dann erstellt, wenn eine undefinierte Klassenmethode mit demselben Namen wie eine Instanzmethode aufgerufen wird. Aber diese Instanz wird nirgendwo gespeichert, die ich sehen kann, und nur der Wert .message wird zurückgegeben. Hier ist der relevante Code, wie sie derzeit auf Github definiert:

Klassenmethoden:

def respond_to?(method, include_private = false) #:nodoc: 
    super || action_methods.include?(method.to_s) 
    end 

    def method_missing(method_name, *args) # :nodoc: 
    if respond_to?(method_name) 
     new(method_name, *args).message 
    else 
     super 
    end 
    end 

Instanzmethoden:

attr_internal :message 

# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer 
# will be initialized according to the named method. If not, the mailer will 
# remain uninitialized (useful when you only need to invoke the "receive" 
# method, for instance). 
def initialize(method_name=nil, *args) 
    super() 
    @_mail_was_called = false 
    @_message = Mail.new 
    process(method_name, *args) if method_name 
end 

def process(method_name, *args) #:nodoc: 
    payload = { 
    mailer: self.class.name, 
    action: method_name 
    } 

    ActiveSupport::Notifications.instrument("process.action_mailer", payload) do 
    lookup_context.skip_default_locale! 

    super 
    @_message = NullMail.new unless @_mail_was_called 
    end 
end 
+0

so rspec rails können Sie nicht invairs in Mailer zu testen? Minitest macht ... – pixelearth

+1

Siehe aktualisierte Antwort. –

+0

Das ist nützlich, außer in diesem Fall bin ich nicht sicher, welches Objekt diese Instanzvariablen haben würde. Irgendwelche Ideen? – pixelearth

2

Ich glaube nicht, das möglich ist, zu prüfen, es sei denn, Rails ihre Umsetzung ändert Dadurch wird tatsächlich Zugriff auf das ActionMailer-Objekt (Controller) und nicht nur auf das generierte Mail-Objekt bereitgestellt.

Wie Peter Alfvin wies darauf hin, das Problem ist, dass es die 'Botschaft' kehrt hier:

new(method_name, *args).message 

statt nur den Mailer Rückkehr (Controller) wie folgt aus:

new(method_name, *args) 

Diese post auf der rspec-schiene liste könnte auch hilfreich sein:

Scheint vernünftig, aber unwahrscheinlich zu ändern. Hier ist der Grund. rspec-rails bietet Wrapper für Testklassen, die von Rails bereitgestellt werden. Schienen Funktionstests unterstützen die drei Fragen, die Sie oben darstellen, aber Schienen Mailertests sind unterschiedlich. Von http://guides.rubyonrails.org/action_mailer_basics.html: "Testen Mailer umfasst normalerweise zwei Dinge: Einer ist, dass die Mail in die Warteschlange gestellt wurde, und der andere, dass die E-Mail korrekt ist."

zu unterstützen, was Sie in Mailer Daten sehen möchten, rspec-Schienen würde haben seine eigene ExampleGroup (anstatt die Schienen zu wickeln Klasse) zu schaffen, die fest an Schienen Einbauten gebunden werden müssten. I nahm große Mühe in rspec-rails-2, um Kopplung an öffentliche APIs einzuschränken, und das hatte eine große Auszahlung: Wir hatten nur einen Fall, wo ein Schienen 3.x Freigabe erforderte eine Freigabe von rspec-Schienen (d. h. es gab eine brechende Änderung). Mit rails-2 brach so ziemlich jede Version rspec-rails, weil rspec-rails an Internals gebunden war (rspec-rails ' Fehler, nicht Rails).

Wenn Sie wollen diese Änderung sehen, die Sie benötigen, um es sich in Schienen geändert zu bekommen, an welchem ​​Punkt rspec-Schienen werden gerne die neue und verbesserte MailerTestCase wickeln.

Verwandte Themen