【问题标题】:How to test function inside RxJava flatMap?如何在 RxJava flatMap 中测试函数?
【发布时间】:2019-11-14 22:33:13
【问题描述】:

我在presenter中有如下方法。

public void addNote(int customerId, String body) {
    disposables = RxUtil.initDisposables(disposables);

    if (TextUtils.isEmpty(body)) {
        view.showNoteTextEmpty();
        return;
    }

    if (customerId == Constants.ZERO) {
        view.showNoteError("There is a problem with adding note. Try again!");
        return;
    }

    Disposable disposable = userPrefRepository.getLoggedInUser()
        .subscribeOn(Schedulers.io())
        .map(user -> getNote(body, user))
        .flatMap(note -> customersRepository.addNote(customerId, note))
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(response -> {
            if (response.isSuccessful()) {
                view.onNoteAdded();
            } else if (response.code() == 401) {
                view.handleUnauthorisedError();
            } else {
                view.onNoteNotAdded();
            }
        }, view::handleError);

    disposables.add(disposable);
}

现在我想用以下类对其进行单元测试:

@RunWith(PowerMockRunner.class) @PrepareForTest(TextUtils.class)
public class NoteDetailsPresenterTest extends BaseTest {

    @Rule TrampolineSchedulerRule trampolineSchedulerRule = new  TrampolineSchedulerRule();

    @Mock CustomersRepository customersRepository;
    @Mock UserRepository userRepository;
    @Mock RolesManager rolesManager;
    @Mock NoteDetailsPresenter.View view;

    private NoteDetailsPresenter presenter;

    @Before
    public void setUp() {
        mockTextUtils();
        presenter = new NoteDetailsPresenter(customersRepository, userRepository, rolesManager);
        presenter.setView(view);
    }

    @Test
    public void shouldAddNote() {
        // Given
        User user = User.newBuilder()
            .withUserId(1)
            .build();

        // When
        Mockito.when(userRepository.getLoggedInUser()).thenReturn(Single.just(user));
        Note note = presenter.getNote("Note body", user);
        Response<Note> response = Response.success(200, note);
        Mockito.when(customersRepository.addNote(1, note)).thenReturn(Single.just(response));
        presenter.addNote(1, "Note body");

        // Then
        Mockito.verify(view).onNoteAdded();
    }
}

但它会失败并出现以下异常:

需要但未调用: view.onNoteAdded(); -> 在 com.anstar.presentation.notes.NoteDetailsPresenterTest.shouldAddNote(NoteDetailsPresenterTest.java:56)

但是,还有其他与此模拟的交互: view.handleError( java.lang.NullPointerException: 映射器返回的single为null ); -> 在 io.reactivex.internal.observers.ConsumerSingleObserver.onError(ConsumerSingleObserver.java:46)

我该如何解决?是关于 map 和 flatMap 转换的问题吗?

【问题讨论】:

    标签: android unit-testing rx-java rx-java2 rx-android


    【解决方案1】:

    似乎无法读取模拟。尝试在参数上加上any()

    而不是这个:

    Mockito.when(customersRepository.addNote(1, note)).thenReturn(Single.just(response));
    

    使用any():

    Mockito.when(customersRepository.addNote(anyInt(), any(Note.class))).thenReturn(Single.just(response));
    

    为什么 mock 无法读取?

    如果参数是原始数据类型(字符串、整数、双精度等),您可以只传递确切的参数(在您的情况下,第一个参数是整数,1)并且模拟将被读取。但是在对象中(在您的情况下,Note 对象),即使您具有相同的确切参数,它们也会有不同的hashCode(),因此无法读取模拟。解决方案是接受 any() 参数指定类类型:any(Note.class)

    【讨论】:

    • 它有效,谢谢。你能解释一下,让我更好地理解吗?为什么无法读取,因为我提供了 1 和 note 对象?
    • 我已经根据我的观察更新了我的答案。这可能不是完全正确的解释,但它与对象 hashCode() 有关
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2018-11-22
    • 2020-02-03
    • 2018-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多