但是,与此模拟还有其他交互:

However, there were other interactions with this mock:

所以我有问题,这是我的演示者代码:

@Override
public void login(String phone, String password) {
    loginView.showProgress();
    compositeSubscription.clear();

    Subscription subscription = service.login(phone,password)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(data -> {
                //Log.d("Login", new Gson().toJson(data));
                loginView.hideProgress();
                if(data.getSt()==1)
                {
                    saveDataPartner(data.getData().getId_hos(), data.getData().getName(), data.getData().getEmail(), data.getData().getPhone(), data.getData().getAvatar());
                    loginView.navigateToMainMenu();
                }
                else {
                    loginView.showMessage(data.getMsg());
                }
            }, error -> {
                loginView.hideProgress();
                loginView.showMessage(ErrorUtils.getErrorMessage(error));
            });
}

我想用这段代码测试一下:

@Before
public void setUp() throws Exception {
    RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
        @Override
        public Scheduler getMainThreadScheduler() {
            return Schedulers.immediate();
        }
    });
}

@After
public void tearDown() {
    RxAndroidPlugins.getInstance().reset();
}

@Test
public void clickBtnLogin() {

    User user = new User();
    user.setName("aa");
    ResultAPIUser<User> ru = new ResultAPIUser<User>();

    ru.setData(user);
    ru.setMsg("example message");
    ru.setSt(1);

    when(service.login("aa","aa")).thenReturn(Observable.just(ru));

    loginPresenter.login("aa","aa");

    verify(loginView).showProgress();
    verify(loginView).hideProgress();
    verify(loginView).navigateToMainMenu();
}

所以我把st的值设置为1,我觉得应该可以。但我明白了:

Wanted but not invoked:
loginView.hideProgress();
-> at     hos.wellhos.com.hosapps.login.LoginPresenterTest.clickBtnLogin(LoginPresenterTest.java:79)

 However, there were other interactions with this mock:
 loginView.setPresenter(
     hos.wellhos.com.hosapps.login.LoginPresenter@4313f5bc
 );
 -> at hos.wellhos.com.hosapps.login.LoginPresenter.<init>    (LoginPresenter.java:43)

谁能帮我解决这个问题,我觉得这有什么棘手的问题?

这可能是线程问题。您的 Observable 正在 Schedulers.io 上订阅 即使您随后切换到主线程来处理结果,这也需要时间。因此,在订阅完成之前正在处理您的验证声明。

有几种方法可以解决这个问题:

动态调度程序

无需将所需的调度程序直接传递给您的 subscribeOnobserveOn 方法,您可以定义为您保存这些的成员变量:

Scheduler ioScheduler;
Scheduler mainThreadScheduler;

并在 observeOn/subscribeOn 语句中使用它们:

.subscribeOn(ioScheduler)
.observeOn(mainThreadScheduler)

然后您可以像在 class 构造函数中设置任何其他依赖项一样设置它们。对于生产代码,您可以将它们设置为正常的 Schedulers.io() & AndroidSchedulers.mainThread() 但是在您的测试代码中,您可以将它们都设置为 Schedulers.immediate() (这只是 returns 当前的调度程序线程)。

RxJavaHooks

在 RxJava 1.1.7 中引入了一个名为 RxJavaHooks 的实用程序 class,它允许您挂接到 RxJava 生命周期的多个部分。这些钩子之一是 setOnIOScheduler() 方法。这允许您更改 Schedulers.io.

返回的 Scheduler

在您的情况下,您想将其更改为 Schedulers.immediate():

RxJavaHooks.setOnIOScheduler(scheduler -> Schedulers.immediate());

完成测试后,您需要致电:

RxJavaHooks.reset();

这只会让一切恢复正常,这样这一变化就不会干扰您在其他地方 运行 进行的其他测试。