2017-10-04 73 views
1

這個問題以前已經問過,但現有的答案並不完全適用於我的情況。「Mockito 0 matchers預計,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); 
        } 
       } 
     ); 
    } 
} 

我有以下的測試案例:

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預期的比賽?其他答案建議用any(...)isA(..)替換eq(..)。首先,我不相信這是適用的,因爲錯誤是沒有匹配器預計在第一位;其次,我試過了,問題依然存在。

如果有人能解釋爲什麼會有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'的。(我有點驚訝,它說「3匹匹配者記錄」而不是「4匹配匹配者記錄」,但0預期是一個相當不錯的信號,你沒有驗證你的想法。) –

回答

2

Ahahaha,找到它!您在測試文件的第六個帶註釋的字段中錯誤地使用@Mock ArgumentCaptor

@Mock private ArgumentCaptor<AccountDataSource.VerifyMobileNumberCallback> 
    verifyMobileNumberCallbackCaptor; 

擁有的Mockito不是特例,它自己的基礎設施,所以它並沒有抓到你試圖嘲笑自己的Mockito的事實。通過在verify呼叫中間調用方法ArgumentCaptor.capture(),Mockito假定您確實試圖驗證對capture的呼叫。儘管其巧妙的語法

,的Mockito真的只是一個狀態機,其中呼叫到verify(...)開始驗證,每次調用匹配推送匹配描述onto an internal stack,然後到的Mockito模擬下一次調用觸發驗證。 Mockito在參數匹配器堆棧中看到三個匹配器,用於capture的零參數調用。這就是爲什麼有3個匹配器記錄,並預期0。

將該註釋切換到@Captor,你應該很好去。

+1

Facepalm!當然,這一切現在都有道理。非常感謝您花時間來發現這一點 –

相關問題