基本的に何が起こっているのかというと、rspec仕様で統合テストを行っているとき、パスワードのリセット機能をテストしているとき、そしてサードパーティのapi呼び出しを使用して電子メールを送信しているときです。サードパーティのAPIを信頼してメールを送信し、応答を完全に無視したいと思います。
これが私が現在使用しているコードですが、send_password_reset(サードパーティのAPI呼び出しが含まれている場所)への呼び出しがMochaによると「呼び出されていない」ため、まだ電子メールを送信しているだけでなく失敗しています
before(:each) do
@client = Factory(:user_with_clients).clients.first
end
it 'should send out the email(mock) set a temporary password and take them back to the login page' do
# WHEN THE MOCK WAS MOVED HERE THE SPEC PASSSED
visit '/client_portal/reset_password/new'
fill_in 'email', with: @client.email
click_button 'Send password reset'
# THIS NEEDED TO BE MOVED TO THE TOP OF THE FUNCTION
Client.expects(:send_password_reset).returns(true)
current_path.should eq('/client_portal/login')
page.should have_content('Check your email')
@client.reload
@client.tmp_password.should_not eq(nil)
end
これを作成するために使用されたファクトリを投稿しても、他に何も明らかになるとは思いませんが、それは私がそれを行うのに役立つと思います。
また、Cilent.expectsを@ client.expectsに変更しようとしましたが、同じ問題が発生します。これは実際に私がこれまでに行った最初のモックであるため、私はMochaフレームワークに縛られていません。
また、統合テストでオブジェクトをモックすることは想定されていないことも読みましたが、テストが呼び出されたときに電子メールを送信しない方法がわかりません。
そこに何かを変更する必要がある場合に備えて、そこにもコントローラーアクションを追加する必要があると思っただけです...
def create
client = Client.find_by_email(params[:email])
if client
client.set_tmp_password
if client.send_password_reset
redirect_to '/client_portal/login', notice: 'Check your email for the password reset link'
else
redirect_to '/client_portal/login', notice: 'There was an error resetting your password. Please try one more time, and contact support if it doesn\'t work'
end
else
flash.now[:notice] = 'No account with that email address was found'
render :new
end
end
テストを実行すると、このエラーが発生します
1) Reset a users password user is not logged in valid email address supplied should send out the email(mock) set a temporary password and take them back to the login page
Failure/Error: Client.any_instance.expects(:send_password_reset).returns(true)
Mocha::ExpectationError:
not all expectations were satisfied
unsatisfied expectations:
- expected exactly once, not yet invoked: #<AnyInstance:Client(id: integer, first_name: string, last_name: string, email: string, password_digest: string, signup_charge: decimal, monthly_charge: decimal, active: boolean, created_at: datetime, updated_at: datetime, monthly_charge_day: integer, sold_by_user_id: integer, tmp_password: string)>.send_password_reset(any_parameters)
# ./spec/requests/client_portal/reset_password_spec.rb:14:in `block (4 levels) in <top (required)>'
解決
@Veraticusから以下のコードを使用し、それを仕様の先頭に移動すると、問題が解決しました。