如何在presenter层上编写适当的android单元测试

rem*_*dy. 4 mvp android unit-testing mockito

我假设使用 Model-View-Presenter (MVP) 模式时编写单元测试会容易得多,但我不确定如何开始。我添加了依赖项以开始编写单元测试RoboelectricMockito模拟演示者中使用的所有依赖项。

作为参考,以下是我的演示者登录示例:

public class LoginPresenterImpl implements ILoginPresenter {

@Inject
Bus bus;

@Inject
ISharedPreferencesRepository mSharedPreferencesRepository;

private final String LOG_TAG = "LOGIN_PRESENTER";
private ILoginView loginView;
private LoginInteractorImpl loginInteractor;
private long mLastClickTime = 0;

public LoginPresenterImpl() {
    MyApplication.getObjectGraph().inject(this);
    this.loginInteractor = new LoginInteractorImpl();
}

@Override
public void setLoginView(ILoginView loginView) {
    this.loginView = loginView;

    if(mSharedPreferencesRepository.isLoggedIn()) {
        Log.i(LOG_TAG, "User logged in already");
        this.loginView.navigateToHome();
    }
}

@Override
public void validateCredentials(String username, String password) {
    if(SystemClock.elapsedRealtime() - mLastClickTime < 1000)
        return;
    mLastClickTime = SystemClock.elapsedRealtime();

    if(username.equals("") || username == null) {
        loginView.setUsernameError();
        return;
    } else if(password.equals("") || password == null){
        loginView.setPasswordError();
        return;
    }

    loginView.showProgress();
    loginInteractor.login(username, password, this);
}

@Override
public void onUsernameError() {
    loginView.setUsernameError();
    loginView.hideProgress();
}

@Override
public void onPasswordError() {
    loginView.setPasswordError();
    loginView.hideProgress();
}

@Subscribe
@Override
public void onSuccess(LoginEvent event) {
    if (event.getIsSuccess()) {
        mSharedPreferencesRepository.setLogin(true);
        mSharedPreferencesRepository.setFirstTime(true);
        mSharedPreferencesRepository.setUserId(event.getUserId());

        loginView.navigateToHome();
        loginView.hideProgress();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在进入我的单元测试(尝试):

首先,如果我错了,请纠正我,但是为了开始编写我的测试用例,我需要模拟一些对象: Bus, ISharedPreferencesRepository, ILoginView, LoginInteractorImpl

我最终得到了这样的结果:

@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterImplTest {

    @Mock
    private ILoginView view;

    @Mock
    private LoginInteractorImpl interactor;

    @Mock
    private LoginPresenterImpl presenter;

    @Before
    public void setUp(){

    }


    @Test
    public void shouldShowErrorMessageWhenUsernameIsEmpty() throws Exception {
        when(view.getUsername()).thenReturn("");
        when(view.getPassword()).thenReturn("test");
        presenter.validateCredentials(view.getUsername(), view.getPassword());
    }
}
Run Code Online (Sandbox Code Playgroud)

我对接下来要采取的步骤有点迷茫。我正在尝试loiginView.setOnUsernameError()通过添加来验证该方法是否会在这种情况下被调用,但这在verify(view, times(1)).setUsernameError();我的测试中失败了。

Yai*_*lka 5

我不建议在演示者中使用 Android 类。这将允许您将演示者作为本地单元测试(经典的 java 单元测试)进行测试。

如果您仍想在演示器中使用 Android 类,请不要使用 dagger 对演示器依赖项进行属性注入。我要做的就是将它们传递给演示者的构造函数。

然后,模拟所有 Presenter 的依赖项并创建将被测试的 Presenter。您正在嘲笑要测试的演示者。不要那样做,只需创建一个 newLoginPresenterImpl并通过 setUp 方法中的构造函数传递它的所有依赖项以对其进行初始化。

这里有几个简单的演示者测试示例。