"Mockito 0 matchers expected, 3 recorded" - 为什么预期有 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: 参数匹配者的使用无效!0个匹配者预期,有3个记录: ->在... testsubmitcode(verification codeviewModeltests.java:132) ->在... testsubmitcode(verification codeviewModeltests.java:133) ->在... testsubmitcode(verification codeviewmodeltests.java:134)

如果将匹配器与原始值结合在一起,则可能发生此例外: //不正确: somemethod(AnyObject()," RAW String");使用匹配项时,所有参数都必须由匹配者提供。例如: //正确的: somemethod(AnyObject(),eq("字符串by Matcher"));

有关更多信息,请参见Matchers类的Javadoc。

在 ... verification codeviewModeltests.testsubmitcode(verification codeviewmodeltests.java:135)

我不明白的是为什么它说0匹配预期?其他答案建议用any(...)isA(..)替换eq(..)。首先,我不认为这是适用的,因为错误是首先没有匹配者。其次,我已经尝试过它,并且问题仍然存在。

如果有人可以解释为什么预期有0个匹配者以及如何解决此问题,我会很感激。

update

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());
            }
        });
    }
}

ahahaha,找到了它!您正在测试文件的第六个注释字段中错误地使用@Mock ArgumentCaptor

@Mock private ArgumentCaptor<AccountDataSource.VerifyMobileNumberCallback>
    verifyMobileNumberCallbackCaptor;

Mockito并没有特别限制自己的基础架构,因此它并没有抓住您正在尝试嘲笑Mockito本身的事实。通过在verify呼叫中间调用方法ArgumentCaptor.capture(),Mockito假设您实际上正在尝试验证capture的调用。

尽管语法巧妙,但Mockito实际上只是一台状态机,在该机器中,verify(...)的呼叫开始验证,每个呼叫对Matcher的调用都会将匹配器描述推到内部堆栈,然后将下一个调用对Mockito Mock触发触发器确认。Mockito在参数匹配器堆栈上看到了三个匹配项,以拨打capture的零arg调用。这就是为什么记录了3个匹配者,还有0个预期。

切换注释到@Captor,您应该很好。

相关内容

  • 没有找到相关文章

最新更新