首页 > 解决方案 > (RxJava2)Single.blockingGet() 不适用于单元测试

问题描述

我为返回 Rx Single 的交互器方法创建单元测试。Single 必须异步返回一个用户的 bean。我尝试为 Single 调用 blockingGet() 但 bean 没有返回,因为测试无休止地工作。我检查了断点,发现 bean 已创建但没有返回。我还尝试为 Single 调用 test().values().get(0) 但它不包含 bean。断点没有调用。

我可以理解这是什么问题。我需要帮助来解决它。

交互器中的方法。

    public Single<UserBean> verifyUser() {
    String jwt = getJWTToken();
    if (TextUtils.isEmpty(jwt)) {
        return Single.error(new EmptyJWTException());
    }
    if (!checkConnectionInfo()) {
        return Single.error(new NotNetworkConnectedException());
    }
    return Single.create((SingleOnSubscribe<UserBean>) emitter -> {
        UserBean resultBean = mAuthenticationRepository.verifyUserByJwt(jwt);
        if (resultBean != null && !TextUtils.isEmpty(resultBean.getId())) {
            emitter.onSuccess(resultBean);
        } else {
            emitter.onError(new RequestToServerException());
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}

单元测试。

@RunWith(MockitoJUnitRunner.class)
public class AuthenticationInteractorTest {

@Mock
private Application mApplication;
@Mock
private IAuthenticationRepository mAuthenticationRepository;
@Mock
private SharedPreferences mSharedPreferences;
@Mock
private ConnectivityManager mConnectivityManager;
@Mock
private NetworkInfo mNetworkInfo;
private AuthenticationInteractor mInteractor;

@Before
public void setUp() {
    mInteractor = new AuthenticationInteractor(mAuthenticationRepository, mApplication);
}

@Test
public void verifyUserTest() {
    String jwt = "jwt";
    UserBean userBean = createUserBean();
    when(mApplication.getSharedPreferences(AuthenticationInteractor.SHARED_PREFS, Context.MODE_PRIVATE)).thenReturn(mSharedPreferences);
    when(mSharedPreferences.getString(AuthenticationInteractor.TOKEN_KEY, null)).thenReturn(jwt);
    when((ConnectivityManager) mApplication.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityManager);
    when(mConnectivityManager.getActiveNetworkInfo()).thenReturn(mNetworkInfo);
    when(mNetworkInfo.isConnected()).thenReturn(true);
    when(mAuthenticationRepository.verifyUserByJwt(jwt)).thenReturn(userBean);
    UserBean bean = mInteractor.verifyUser().blockingGet();
    assertEquals(userBean, bean);
}

private UserBean createUserBean() {
    UserBean userBean = new UserBean();
    userBean.setMetaId("1539762652616:940c29e6d716:15:jmt4z02l:11182");
    userBean.setJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im1hZ2F6b240aWtAeWFuZGV4LnJ1IiwiY3MiOiI1OWEwNDA2MTgzNDAwMDAwIiwiaWF0IjoxNTM5NzYyNjUyLCJhdWQiOiIqLmxvY2FsaG9zdCIsImlzcyI6Im1zLXVzZXJzIn0.2AcuLZjR_-GyWAFen7JczJ5-W37zQWGbnRRErGLqDEY");
    userBean.setId("test@test.test");
    userBean.setType("user");
    userBean.setUserName("test@test.test");
    userBean.setCreated(1535970916310L);
    userBean.setLatestResult("1539676474685");
    userBean.setOnDiet("No");
    return userBean;
}

}

标签: androidunit-testingrx-java2rx-android

解决方案


看起来您没有覆盖正在使用的调度程序。如果不这样做,您几乎肯定会在尝试使用订阅时收到以下错误AndroidSchedulers.mainThread

android.os.Looper 中的方法 getMainLooper 未模拟

为了克服这个问题,您可以创建一个 TestRule ,它允许您为测试指定调度程序,例如以下将重置Schedulers.ioAndroidSchedulers.mainThread使用Schedulers.trampoline.

public class RxSchedulersRule implements TestRule {
    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                RxAndroidPlugins.reset();
                RxJavaPlugins.reset();

                RxAndroidPlugins.setInitMainThreadSchedulerHandler(s -> Schedulers.trampoline());
                RxJavaPlugins.setIoSchedulerHandler(s -> Schedulers.trampoline());

                try {
                    base.evaluate();
                } finally {
                    RxAndroidPlugins.reset();
                    RxJavaPlugins.reset();
                }
            }
        };
    }
}

要在您的测试中使用,您需要声明规则

@Rule public final RxSchedulersRule schedulersRule = new RxSchedulersRule();

推荐阅读