【问题标题】:Mocking concrete class模拟混凝土类
【发布时间】:2016-03-12 19:36:59
【问题描述】:

我正在对连接到服务并返回令牌的 Presenter 类进行单元测试 当用户从调用 REst 服务的异步任务接收到令牌时,主屏幕将启动。如果令牌为空,则会显示错误

public void onSignInButtonClicked() {

    String username = mSigninView.getUsername();


    if (username.isEmpty()) {
        mSigninView.showUsernameError(R.string.username_error);
        return;
    }

    String password = mSigninView.getPassword();
    if (password.isEmpty()) {
        mSigninView.showPasswordError(R.string.password_error);
        return;
    }

    String token = mSigninService.connectToRestServices(username, password);
    if (token != null) {
        mSigninView.startHomeActivity(token);
    } else {
        mSigninView.showLoginError(R.string.login_error);
    }
}

对于单元测试:

@Test
public void shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect() throws Exception {
    Mockito.when(mView.getUsername()).thenReturn("test@test.com");
    Mockito.when(mView.getPassword()).thenReturn("test");
    Mockito.when(mService.connectToRestServices("test@test.com", "test")).thenReturn("test");
    mPresenter.onSignInButtonClicked();
    Mockito.verify(mView).startHomeActivity("test");
}

测试时出错

需要但未调用: signin_View.startHomeActivity("test"); -> 在 com.ssd.cypress.uimobile.SigninPresenterTest.shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect(SigninPresenterTest.java:72)

在代码中 字符串令牌 = mSigninService.connectToRestServices(用户名,密码); 它连接到具体类并且令牌为空。有没有办法模拟这个 connectToService 以便它返回 SomeValue。

【问题讨论】:

  • 如果我没记错的话,你的令牌不为空,它会尝试执行 startHomeActivity("test")。所以它确实返回“SomeValue”。尝试在调试模式下执行单元测试,看看在进行空比较之前得到的 token 值到底是什么。
  • 感谢您的回复!!!令牌始终为空。在我的代码中,演示者的构造函数是
  • public SigninPresenter(Signin_View view) { mSigninView = view; mSigninService = new Sign_in_service(); }
  • 这里当演示者被模拟时,它会创建一个我无法控制的新服务对象。这个应用程序被编写为 MVP 模式,其中服务在 Presenter 层中初始化。此对象返回的令牌始终为 null。
  • 请告诉我当构造函数像上面那样时如何对Presenter类进行单元测试?

标签: java android unit-testing mockito


【解决方案1】:

您的模拟服务协作者mService 在测试期间永远不会被调用,因为它没有传递或注入到被测类中。根据您的 cmets,我认为您意识到了这一点。

按照我的理解重述您的 cmets,您想使用协作者的模拟 - Sign_in_service 的实例 - 但您不能这样做,因为协作者是由您创建的而不是传递给您的测试类-SigninPresenter

问题是你SigninPresenter的构造函数,它不应该负责创建一个协作者。看起来您拥有相关代码,因此您可以更改设计。

我建议您将SigninPresenter 构造函数替换为以下内容:

    public static SigninPresenter createSigninPresenterWithService(Signin_View view) {
        return new SigninPresenter(view,  new Sign_in_service());
    }

    protected SigninPresenter(Signin_View view, Sign_in_service service) { 
        mSigninView = view; 
        mSigninService = service; 
    }  

为了你的测试,你可以调用构造函数并传入一个服务的mock来初始化mPresenter,即:mPresenter = new SignInPresenter(mView, mService)。在您当前调用SigninPresenter 的构造函数的生产代码中,您可以将构造函数调用new SigninPresenter(view) 替换为对静态工厂方法createSigninPresenterWithService(view) 的调用。

【讨论】:

  • 非常感谢您的建议。为我工作。
  • 不客气。在这种情况下,请点击左侧的复选标记,选择我的答案作为您问题的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2017-08-02
  • 2013-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多