2016-09-09 7 views
0

マイテスト"should call #logout_all"RSPEC:オブジェクトが

expected: 1 time with any arguments 
received: 0 times with any arguments 

で失敗しているが、私はrails console直接User.verify_from_tokenを呼び出すとき、私は#logout_allが呼び出されていることを見ることができるクラスメソッド試験からメソッド呼び出しを受信して​​いない(私は追加#logout_allからputs声明)

RSpec.describe User, type: :model do 
    describe ".verify_from_token" do 
     let(:user) {FactoryGirl.create(:user, verified: false)} 

     it "should return the user if found" do 
     token = user.to_valid_token 
     expect(User.verify_from_token token).to eq(user) 
     end 

     it "should verify the user" do 
     token = user.to_valid_token 
     User.verify_from_token token 
     expect(user.reload.verified).to eq(true) 
     end 

     it "should call #logout_all" do 
     token = user.to_valid_token 
     expect(user).to receive(:logout_all) 
     User.verify_from_token token 
     end 
    end 
end 


class User < ApplicationRecord 

... 

    def self.verify_from_token token 
    user = from_token token 
    if user 
     user.update_attribute(:verified, true) 
     user.logout_all 
     user 
    else 
     nil 
    end 
    end 

... 
    def logout_all 
    update_attribute(:token_timestamp, Time.now) 
    end 
end 

私は少しテストを手直しした場合、それが正常に動作します。

it "should call #logout_all" do 
    token = user.to_valid_token 
    t1 = user.token_timestamp 
    User.verify_from_token token 
    expect(t1 < user.reload.token_timestamp).to eq(true) 
    end 
+0

あなたの 'expect'と' User.verify_from_token token'の順序​​が間違っています。今すぐ最初に呼び出しを受け取り、次に期待しているメソッドを呼び出すメソッドを呼び出します。 – Kkulikovskis

+0

いいえ、実装は正しいです。 –

+1

FWIW実装よりも動作をテストしているので、とにかくテストの2番目のバージョンが好きです。しかし、なぜ元のバージョンが失敗しているのか分かりません。おそらくあなたは 'before'ブロックか' spec_helper.rb'の面白いコードを持っていますか?おそらく 'User#from_token'メソッドが実際にユーザオブジェクトを返すのではないでしょうか?私はそれをもう少しデバッグしてデバッグする必要があります。 –

答えて

1

問題は、一人のユーザーの期待を設定することですが、メソッドの呼び出しは、のユーザーに発生します。これです。

user = from_token token 

あなたはfrom_tokenの実装を示さなかったが、私はそれがデータベースからユーザーをロードすることを賭けて喜びました。現在、データベースには1人のユーザーしか存在せず、論理的には、これらの2つの変数は同じエンティティを表します。しかし、物理的には、それらはまだメモリ内の2つの異なるオブジェクトです。自然に期待は満たされていません。

+0

'token = user.to_valid_token'のため、これはうまくいくと思うでしょう...理論的には、' User#to_valid_token'と 'User#from_token'の実際の実装に依存します。 –

+0

@SergioTulentsev良いキャッチ。 'User.verify_from_token'はJWTをデコードしてidを取り出し、' User.find(id) 'でユーザを返します。そして、そのユーザに対して '#logout_all'を呼び出します。 – sheepdog

1

あなたはこれをしなければならない:

それは前に言っていたよう
it "should call #logout_all" do 
    token = user.to_valid_token 
    allow(User).to receive(:from_token).once.with(token).and_return(user) 
    expect(user).to receive(:logout_all) 
    User.verify_from_token token 
end 

、この方法は、あなたがテ期待を設定されていない1、新しいユーザーインスタンスで呼び出されます。 "from_token"クラスのメソッドをスタブして、データベースから同じIDを持つ別のインスタンスではなく、メッセージを受信して​​いると同じオブジェクトを返す必要があります。

+0

これは実際にはとても良い解決策です!私は '#logout_all'(*他の場所でテストされるべき)の*動作*をテストするのではなく、'#logout_all'が呼び出されたかどうかをテストするのが好きです。 – sheepdog

関連する問題