【问题标题】:Mockito InvalidUseOfMatchersException, when trying to unit test method with custom Callback as a parameterMockito InvalidUseOfMatchersException,当尝试使用自定义回调作为参数对方法进行单元测试时
【发布时间】:2017-07-18 09:23:27
【问题描述】:

我正在学习 Android MVP 架构并尝试使用 Mockito/JUnit 测试一些方法。我正在从本教程中学习:

https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex

我在我的 Android MVP 架构类型应用中测试 Presenter 方法时遇到问题。

这是我的 Presenter 类:

public class ForgotPasswordPresenter implements ForgotPasswordMVP.Presenter{
private ForgotPasswordMVP.View view;
private ForgotPasswordMVP.Model model;


public ForgotPasswordPresenter(FirebaseAuthService firebaseAuthService, ForgotPasswordMVP.Model model) {
    this.model = model;
}

@Override
public void setView(ForgotPasswordMVP.View view) {
    this.view = view;
}

@Override
public void sendButtonClicked() {

    if(view != null) {
        view.showProgressBar();
        model.sendEmail(view.getEmail(), new 
        ForgotPasswordMVP.Model.SendForgotEmailCallback() {
            @Override
            public void onEmailSent(boolean sent) {
                if(sent) {
                    view.hideProgressBar();
                    view.showEmailSent();
                }
                else{
                //show some error on UI
                }
            }
        });
    }
  }
}

这是 MVP.Model 结构的合约接口。我定义了自定义回调:

   interface Model{
   interface SendForgotEmailCallback {
        void onEmailSent(boolean sent);
    }

    void sendEmail(String email, @NonNull SendForgotEmailCallback SendForgotEmailCallback) ;
}

在我的模型中,我做这样的事情,我只是使用 Firebase 来重置密码:

public class ForgotPasswordModel implements ForgotPasswordMVP.Model{

private FirebaseAuthService firebaseAuthService;

public ForgotPasswordModel(FirebaseAuthService firebaseAuthService) {
    this.firebaseAuthService = firebaseAuthService;
}

@Override
public void sendEmail(String email, @NonNull final SendForgotEmailCallback SendForgotEmailCallback) {
    firebaseAuthService.sendPasswordResetEmail(email).addOnCompleteListener(new OnCompleteListener<Void>() {
        @Override
        public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    SendForgotEmailCallback.onEmailSent(true);
                }
                else{
                    SendForgotEmailCallback.onEmailSent(false);
                }
        }
    });
}
}

现在,我想测试负责发送电子邮件的方法,只需单击发送按钮。这是我的测试原型:

public class ForgotPasswordPresenterTest {

@Mock
ForgotPasswordMVP.Model model;

@Mock
ForgotPasswordMVP.View view;

@Mock
FirebaseAuthService firebaseAuthService;

@Captor
private ArgumentCaptor<ForgotPasswordMVP.Model.SendForgotEmailCallback> sendForgotEmailCallbackArgumentCaptor;


private ForgotPasswordPresenter forgotPasswordPresenter;

@Before
public void setupForgotPasswordPresenter(){
    MockitoAnnotations.initMocks(this);

    forgotPasswordPresenter = new ForgotPasswordPresenter(firebaseAuthService, model);
    forgotPasswordPresenter.setView(view);
}

  @Test
public void sendButtonClicked_shouldShowEmailSent(){

    when(view.getEmail()).thenReturn("test@mail.com");

    forgotPasswordPresenter.sendButtonClicked();

    verify(model).sendEmail(view.getEmail(), sendForgotEmailCallbackArgumentCaptor.capture());
    sendForgotEmailCallbackArgumentCaptor.getValue().onEmailSent(true);

    verify(view).showEmailSent();

}

}

所以,当涉及到 verify(model).sendEmail... 时,它崩溃了,并且出现了 Mockito 的这个异常:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 参数匹配器的使用无效! 预计 2 个匹配器,记录 1 个: -> 在 com.example.app.ui.login.ForgotPasswordPresenterTest.sendButtonClicked_shouldShowEmailSent(ForgotPasswordPresenterTest.java:53) 如果匹配器与原始值组合,则可能会发生此异常: //不正确: someMethod(anyObject(), "原始字符串"); 使用匹配器时,所有参数都必须由匹配器提供。 例如: //正确的: someMethod(anyObject(), eq("String by matcher"));

有关更多信息,请参阅 Matchers 类的 javadoc。

谁能帮我解决这个问题?我是初学者,想弄清楚,但现在真的不知道。

【问题讨论】:

    标签: java android mockito mvp


    【解决方案1】:

    由于您使用capture()(被视为匹配器)捕获参数,因此您必须对verify 中的所有其他原始值使用eq。在您的测试中view.getEmail() 返回原始值(“test@mail.com”),因此您的验证将更改为:

    verify(model).sendEmail(eq(view.getEmail()), sendForgotEmailCallbackArgumentCaptor.capture());
    

    请注意,您现在将验证用eq 包裹的view.getEmail()

    要记住的一件好事是:如果您对任何方法参数使用匹配器,则应使用匹配器验证所有参数(使用 eq 获取原始值)。

    【讨论】:

    • 感谢它的工作!我只能在 9 分钟后接受你的回答,谢谢
    • 我现在有同样的问题,当我有 2 个参数时。 gist.github.com/oksett/78b76637257851d326ac8f8f5b93b201你能帮帮我吗?
    • 不管你有多少参数,它应该和以前一样工作。
    • 不幸的是它没有,它是同样的错误。唯一的区别是,我用 3 个参数测试该方法,而不是像以前那样用 2 个。有什么想法吗?
    • 错误是否显示“预期 3 个匹配器,已记录 1 个”或类似的内容?从你的 sn-p 看,它应该可以工作
    猜你喜欢
    • 2023-03-06
    • 2018-06-20
    • 2017-06-13
    • 1970-01-01
    • 2017-11-22
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多