我正在尝试测试用Rxjava运算符之一的回调函数编写的代码。这是我想要测试的原始代码
@Override
public Observable<List<User>> getUsers() {
UserDataStore userDataStore = userDataStoreFactory.createCloudDataStore();
return userDataStore.getUsers().map(userEntityDataMapper::transform);
}
在上面的代码中,有一个"map"运算符,其回调函数将通过调用userEntityDataMapper.transform()
方法将原始对象转换为另一个对象。在这里,我想测试用户实体数据映射器的转换方法必须是调用。这是我尝试检查userEntityDataMapper.transform()
方法调用与否的代码。
@Test
public void testGetUsersHappyCase() {
List<UserEntity> userEntityList = new ArrayList<>();
userEntityList.add(new UserEntity());
given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
List<User> userList = new ArrayList<>();
given(mockUserEntityDataMapper.transform(userEntityList)).willReturn(userList);
given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);
Observable observable = userDataRepository.getUsers();
verify(mockUserDataStoreFactory).createCloudDataStore();
verify(mockUserDataStore).getUsers();
TestObserver<List<UserEntity>> testObserver = new TestObserver<>();
TestScheduler testScheduler = new TestScheduler();
observable.subscribeOn(testScheduler).observeOn(testScheduler).subscribeWith(testObserver);
verify(mockUserEntityDataMapper).transform(any(List.class));
}
我在堆栈溢出和论坛上检查了许多类似的问题,但无法找到我问题的确切解决方案。
更新:这是我为解决问题所做的更改。
@Test
public void testGetUsersHappyCase() {
List<UserEntity> userEntityList = new ArrayList<>();
userEntityList.add(new UserEntity());
given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
List<User> userList = new ArrayList<>();
given(mockUserEntityDataMapper.transform(userEntityList)).willReturn(userList);
userDataRepository.getUsers().test().assertNoErrors();
verify(mockUserDataStoreFactory).createCloudDataStore();
verify(mockUserDataStore).getUsers();
verify(mockUserEntityDataMapper).transform(userEntityList);
}
感谢@tynn test(( 方法的提示。我在 https://github.com/googlesamples/android-architecture-components 的BasicRxJavaSample演示中也发现了同样的东西。
您必须订阅流才能执行它。这就像在可观察对象上调用test()
一样容易完成。这将为您提供一个TestObserver
。
除此之外,您没有任何理由使用 TestScheduler
.在您的情况下,这实际上是问题所在。您没有调用triggerActions()
,因此您的流根本不执行。
如果您没有修改正在测试的代码中的任何计划程序,则在测试中也忽略这些计划程序。如果需要更改它,最好创建一个规则,将每个Schedulers
设置为同步版本。您可以在RxJavaPlugins
类中找到此的二传手。
Tynn的回答是正确的,你应该听听那里的建议。重构的测试如下所示:
@org.junit.Test
public void testUserDataRepository() throws Exception {
//arrange
List<UserEntity> userEntityList = new ArrayList<>();
userEntityList.add(new UserEntity());
given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
List<User> userList = new ArrayList<>();
given(mockUserEntityDataMapper.transform(userEntityList)).willReturn(userList);
given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);
//act
TestObserver<List<User>> testObservable = userDataRepository.getUsers().test();
//assert
verify(mockUserDataStoreFactory).createCloudDataStore();
verify(mockUserDataStore).getUsers();
verify(mockUserEntityDataMapper).transform(any(List.class));
}
然而,这种类型的白盒测试存在更大的问题 - 测试已经退化为被测系统的重新实现。
如果UserEntityDataMapper
是轻量级的,您可以在测试中使用它的真实版本。然后你的测试变成了一个黑盒测试,可以说有更多的价值。您将知道对UserEntityDataMapper#transform
的调用是通过对List<User>
正确结果的断言发生的:
@org.junit.Test
public void testUserDataRepository() throws Exception {
//arrange
List<UserEntity> userEntityList = new ArrayList<>();
userEntityList.add(new UserEntity());
given(mockUserDataStore.getUsers()).willReturn(Observable.just(userEntityList));
List<User> userList = new ArrayList<>();
given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);
//act
TestObserver<List<User>> testObservable = userDataRepository.getUsers().test();
//assert
testObservable.assertResult(userList);
}