ActionMailer::Baseをインスタンス化できない
メモ
ActionMailerの単体テストを書こうと思い、最初はActionMailer.deliver_???のテストを書いたが次の点が嫌だなと思った。
・deliver_???は自分で書いたコードではない(???が自分で書いたコードだ)
・???で設定したビューで使用することを設定したインスタンス変数の中身をテストするのにdeliver_???が返すオブジェクトのbodyメソッドを調べなければいけない。つまりActionMailerの単体テストを書きたいのにビューに依存したテストを書くことになる。
・テストがやや冗長になる。
以上のことからもっとシンプルに単体テストを書くためにActionMailer::Baseの継承クラスをインスタンス化して直接自分が書いた???メソッドを呼び出そうと考え、以下のようなコードを書いた。
class InquiryMailer < ActionMailer::Base def reply(user) @body[:message] = 'テスト' end end describe InquiryMailer, "#replyを実行した場合" do befor(:each) do @inquiry_mailer = InquiryMailer.new @inquiry_mailer.reply(User.new) end it "@body[:message]はテストであること" do body = @inquiry_mailer.instance_variable_get(:@body) body[:message].should == 'テスト' end end
しかし残念ながらInquiryMailer.newの時点で期待通り動かない。つまりインスタンス化できず、@inquiry_mailerにはnilが代入される。
ActionMailer::Baseのinitializeメソッドのソースを見てみると次の通り第一引数を渡さないとダメみたい。
def initialize(method_name=nil, *parameters) #:nodoc: create!(method_name, *parameters) if method_name end
それで引数を渡した。
@inquiry_mailer = InquiryMailer.new(:reqly, User.new)
それでもNoMethodError: undefined method `mailer' for #
これ以上ActionMailerの詳細に突っ込むのが嫌になったので最初のdeliver_???をテストすることにした。