【问题标题】:test rxjava callback function测试rxjava回调函数
【发布时间】:2018-06-16 02:39:09
【问题描述】:

我正在尝试测试用 Rxjava 运算符之一的回调函数编写的代码。这是我要测试的原始代码

@Override
public Observable<List<User>> getUsers() {
    UserDataStore userDataStore = userDataStoreFactory.createCloudDataStore();
    return userDataStore.getUsers().map(userEntityDataMapper::transform);
}

在上面的代码中有一个“map”操作符,它的回调函数会通过调用userEntityDataMapper.transform()方法将原始对象转换为另一个对象。 这里我想测试一下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));
}

我在 stackoverflow 和论坛上检查了许多类似的问题,但无法为我的问题找到确切的解决方案。

更新: 这是我为解决问题所做的更改。

@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 演示中也发现了同样的东西。

【问题讨论】:

  • 你在日志中得到了什么?
  • 那么您的问题是什么?如果此测试失败,您还会收到一条消息。请同时发布。

标签: android unit-testing mockito rx-java2


【解决方案1】:

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&lt;User&gt;的正确结果的断言发生的:

@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);
}

【讨论】:

  • David Rawson 好主意,但是如何在不提供真实版本的结果数据的情况下匹配真实版本的结果(在本例中为 List)? UserEntityDataMapper#transform 有很多代码可以将 UserEntity 的每个字段转换为 User 类并附加到列表中
  • @Dharmendra 您可以提供一个假的List&lt;UserEntity&gt; 并在其上运行真正的UserEntityDataMapper#transform 以生成预期的List&lt;User&gt;,或者更好的是,手动构建生成的列表。手动构建预期的List&lt;User&gt; 将是更好的黑盒测试,因为您的预期结果将独立于测试步骤
  • 但我想这可以在我们为 UserEntityDataMapper 类本身编写测试时覆盖。那么为 UserEntityDataMapper 编写测试将是对 transform 方法的实际测试,它不会被视为黑盒测试吗?
【解决方案2】:

您必须订阅流才能执行它。这可以像在 observable 上调用 test() 一样简单。这将为您提供TestObserver。

除此之外,您没有任何理由使用TestScheduler。在你的情况下,这实际上是问题所在。您没有调用triggerActions(),因此您的流根本没有执行。

如果您不修改正在测试的代码中的任何调度程序,则在您的测试中也忽略这些。如果您需要更改它,您最好创建一个规则,将Schedulers 设置为每个同步版本。您可以使用 RxJavaPlugins 类找到此设置器。

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 2019-09-21
    • 1970-01-01
    • 2019-11-14
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2018-11-15
    相关资源
    最近更新 更多