2017-10-04 24 views
1

この質問は以前に聞かれましたが、既存の回答は私の状況にはあまり適用されません。"Mockito 0マッチャーが予想され、3レコーディングされました" - なぜ0マッチャーが予想されますか?

私はsubmitCode()メソッドをテストしたいと思います:

public class VerificationCodeViewModel{ 

    //Input 
    public final ObservableField<String> verificationCode   = new ObservableField<>(); 

    //Output 
    public final ObservableField<String> requestError    = new ObservableField<>(); 
    public final ObservableBoolean loading       = new ObservableBoolean(); 
    public final ObservableField<LoginCredentials> loginCredentials = new ObservableField<>(); 

    @NonNull private final Context context; 
    @NonNull private final UnverifiedUser unverifiedUser; 
    @NonNull private final CampaignRepository campaignRepository; 
    @NonNull private final AccountRepository accountRepository; 
    @NonNull private final VerificationCodeNavigator navigator; 

    public VerificationCodeViewModel(@NonNull Context context, 
            @NonNull UnverifiedUser unverifiedUser, 
            @NonNull CampaignRepository campaignRepository, 
            @NonNull AccountRepository accountRepository, 
            @NonNull VerificationCodeNavigator navigator) { 

     this.context = context; 
     this.unverifiedUser = unverifiedUser; 

     this.campaignRepository = campaignRepository; 
     this.accountRepository = accountRepository; 
     this.navigator = navigator; 
    } 

    public void submitCode() { 

     loading.set(true); 

     String sourceCampaign = null; 
     if (campaignRepository.getCampaign() != null) { 
      sourceCampaign = campaignRepository.getCampaign().getSource(); 
     } 

     this.accountRepository.verifyMobileNumber(
       this.unverifiedUser, 
       this.verificationCode.get(), 
       sourceCampaign, 
       new AccountDataSource.VerifyMobileNumberCallback() { 
        @Override 
        public void onVerificationSuccess(UnverifiedUser.Entity entity) { 
         loading.set(false); 
         loginCredentials.set(createLoginCredentials()); 
         navigator.finishActivity(true); 
        } 

        @Override 
        public void onVerificationFailure(@Nullable String message) { 
         loading.set(false); 
         requestError.set(message); 
        } 
       } 
     ); 
    } 
} 

をI、次のテストケースを持っている:

public class VerificationCodeViewModelTests { 

    private VerificationCodeViewModel viewModel; 

    @Mock private Context context; 

    @Mock private UnverifiedUser unverifiedUser; 

    @Mock private CampaignRepository campaignRepository; 

    @Mock private AccountRepository accountRepository; 

    @Mock private VerificationCodeNavigator navigator; 

    @Mock private ArgumentCaptor<AccountDataSource.VerifyMobileNumberCallback> verifyMobileNumberCallbackCaptor; 


    @Before 
    public void setupVerificationCodeViewModel(){ 

     MockitoAnnotations.initMocks(this); 

     viewModel = new VerificationCodeViewModel(
       context, 
       unverifiedUser, 
       campaignRepository, 
       accountRepository, 
       mock(VerifyMobileNumberActivity.class)//navigator 
     ); 
    } 

    @Test 
    public void testSubmitCode(){ 

     viewModel.verificationCode.set(VERIFICATION_CODE); 
     viewModel.submitCode(); 

     assertTrue(viewModel.loading.get()); 

     verify(accountRepository).verifyMobileNumber(
       eq(unverifiedUser),//line 132 
       eq(VERIFICATION_CODE),//line 133 
       eq(CAMPAIGN_SOURCE),//line 134 
       verifyMobileNumberCallbackCaptor.capture());//line 135 

     UnverifiedUser.Entity entity = mock(UnverifiedUser.Entity.class); 
     when(entity.getId()).thenReturn(ENTITY_ID); 

     verifyMobileNumberCallbackCaptor.getValue().onVerificationSuccess(entity); 

     assertFalse(viewModel.loading.get()); 
     assertEquals(viewModel.loginCredentials.get().getUsername(),UNVERIFIED_USER_EMAIL); 
     assertEquals(viewModel.loginCredentials.get().getPassword(),UNVERIFIED_USER_PASSWORD); 

     verify(navigator).finishActivity(true); 
    } 
} 

私はaccountRepository.verifyMobileNumberが呼び出されることを確認した場合、私は次のエラーを取得します:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 0 matchers expected, 3 recorded: -> at ...testSubmitCode(VerificationCodeViewModelTests.java:132) -> at ...testSubmitCode(VerificationCodeViewModelTests.java:133) -> at ...testSubmitCode(VerificationCodeViewModelTests.java:134)

This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

at ...VerificationCodeViewModelTests.testSubmitCode(VerificationCodeViewModelTests.java:135)

なぜ私は理解できないのですか?0マッチが予想される理由は何ですか?他の答えはeq(..)any(...)またはisA(..)に置き換えることを提案します。 最初に、マッチャーが最初に予想されないというエラーがあるため、それは当てはまりません。 と2番目に、私はそれを試しても問題は解決されません。

誰かが0マッチャーが予想される理由とこの問題を解決する方法を説明できると感謝します。

更新

AccountRepository.verifyMobileNumber()の実装は、次のとおり

AccountRepository.java

public class AccountRepository implements AccountDataSource { 
    @Override 
    public void verifyMobileNumber(@NonNull UnverifiedUser unverifiedUser, 
            @NonNull String verificationCode, 
            @Nullable String sourceCampaign, 
            @NonNull VerifyMobileNumberCallback callback) { 
     this.remoteSource.verifyMobileNumber(unverifiedUser, verificationCode, sourceCampaign, callback); 
    } 
} 

AccountRemoteDataSource.java

public class AccountRemoteDataSource implements AccountDataSource { 

    @Override 
    public void verifyMobileNumber(@NonNull UnverifiedUser unverifiedUser, 
            @NonNull String verificationCode, 
            @Nullable String sourceCampaign, 
            @NonNull final VerifyMobileNumberCallback callback) { 

     accountService().verifyMobileNumber(/*params*/).enqueue(new Callback() { 
      @Override 
      public void onResponse(Response response, Retrofit retrofit) { 
       try{ 
        //parse response 
        callback.onVerificationSuccess(entity); 
       } catch (Exception e) { 
        callback.onVerificationFailure(e.getMessage()); 
       } 
      } 

      @Override 
      public void onFailure(Throwable t) { 
       callback.onVerificationFailure(t.getMessage()); 
      } 
     }); 
    } 
} 
+0

エラーがその行に確実に表示されていますか?エラー全体を投稿してください –

+0

@JuanCruzSoler完全なエラーメッセージを含め、コードスニペットに関連する行をマークしました。 –

+0

これまでのところ、完全かつ十分にラベル付けされたソースをありがとうが、さらに、 'verifyMobileNumber'の実装を投稿してください。それが「最終的」である可能性は非常に高いです。 AccountRepositoryと 'verifyMobileNumber'の両方が' final'でなくてはなりません。(私はちょっと驚きましたが、 "4つのマッチャーが記録されました"の代わりに "3つのマッチャーが記録されています"と言われていますが、0はあなたがあなたが何であるかを確認していないというかなりまともな信号です) –

答えて

2

アハハハ、見つけました!誤ってテストファイルの6番目の注釈付きフィールドに@Mock ArgumentCaptorを使用しています。

@Mock private ArgumentCaptor<AccountDataSource.VerifyMobileNumberCallback> 
    verifyMobileNumberCallbackCaptor; 

Mockitoは特殊ケースに入れていない、独自のインフラを持っているので、それはあなたがMockito自身を欺くしようとしているという事実をキャッチしていません。 verifyコールの途中でメソッドArgumentCaptor.capture()を呼び出すと、Mockitoは実際にcaptureへの呼び出しを確認しようとしているとみなします。

その巧妙な構文にもかかわらず、Mockitoは本当にverify(...)への呼び出しは、整合への各呼び出しは、整合の説明onto an internal stackをプッシュした後、Mockitoモックの次の呼び出しは、検証をトリガー、検証を開始し、単にステート・マシン、です。 Mockitoは、引数が0のargの呼び出しのために、引数マッチャースタックに3つのマッチャーがあるとみなして、captureを呼び出します。そのため、3つのマッチャーが記録され、0が予想されます。

注釈を@Captorに変更してください。あなたはうまくいくはずです。

+1

Facepalm!もちろん、それは今すべて意味があります。それを発見する時間をとってくれてありがとう –

関連する問題