单元测试-验证可观察对象是否已订阅



我已经得到了这样的java代码

 mDataManager.getObservable("hello").subscribe( subscriber );

,我想要verify下面的Observable是.subscribe()

我试着去嘲笑getObservable()verify

 Observable<Response> res = mock(Observable.class);
 when(mDataManager.getObservable("hello")).thenReturn(res);
 verify(res).subscribe();

但是有一个错误

Caused by: java.lang.IllegalStateException: onSubscribe function can not be null.
at rx.Observable.subscribe(Observable.java:8167)
at rx.Observable.subscribe(Observable.java:8158)
at rx.Observable.subscribe(Observable.java:7962)
....
Caused by: rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value: omni.neo.hk.omniapiservice.v4.model.external.UserLoginBean.class
at rx.exceptions.OnErrorThrowable.addValueAsLastCause(OnErrorThrowable.java:109)
at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187)
at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:82)
... 48 more

我认为这是不可能的mock一个可观察的,但没有一个模拟的可观察的我不能做verify(res).subscribe()

对于这种情况有什么建议吗?

我发现RxJava提供了一个名为TestSubject的类

你可以像这样创建

private TestScheduler eventsScheduler = new TestScheduler();
private TestSubject<MyEvent> eventObservable = TestSubject.create(eventsScheduler);

这将为您提供返回布尔值的方法hasObservers()

@Test
public void testSubscription(){
    myTestClass.init(eventObservable);
    assertTrue(eventObservable.hasObservers());
}

TestSubject还允许您完美地设置事件发送的时间。

eventObservable.onNext(new MyEvent());
eventsScheduler.triggerActions(); 

也许您可以将Observable.onSubscribe方法与RunTestOnContext规则一起使用?TestContext可以为您提供Async对象,该对象仅在测试完成后终止测试。我认为,如果你把它与Observable#doOnSubscribe结合起来,你可以达到预期的行为。

然而,使用Async有时可能会有点混乱。在下面的例子中,如果这个可观察对象从来没有被订阅过,那么doOnSubscribe函数就永远不会被求值,你的测试也不会终止。

的例子:

@RunWith(VertxUnitRunner.class)
public class SubscriptionTest {
  @Rule
  public RunTestOnContext vertxRule = new RunTestOnContext();
  @Test
  public void observableMustBeSubscribed(final TestContext context) {
    final Async async = context.async();
    final Observable<String> observable = Observable.just("hello").doOnSubscribe(async::complete);
    final Manager mock = mock(Manager.class);
    when(mock.getObservable()).thenReturn(observable);
    mock.getObservable().subscribe();
  }
  interface Manager {
    Observable<String> getObservable();
  }
}

我不确定我是否回答了问题,但我认为所以…

可以创建单元测试来检查是否对一个可观察对象进行了订阅。注意,在RxJava 1中。这是由TestSubject支持的,但是可以通过Subject实现来促进该功能。TestSubject在RxJava 2中被删除。

与其像最初的发布者那样试图模仿可观察对象,不如使用PublishSubject,运行业务逻辑,然后使用publish subject来查看可观察对象是否被观察。下面是一些测试代码,它们验证了这种测试是可能的。当我运行测试时,测试通过了。

请参阅代码注释以了解代码的描述。就我个人而言,这个测试对于验证控制器如何处理数据的其他测试来说似乎是多余的。如果控制器从未订阅并从数据服务接收数据,则其他测试将失败。另一方面,测试取消订阅有助于避免内存泄漏,这可能是高价值的。

import org.junit.Test;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
/**
 * Tests whether it is possible to test whether a controller properly unsubscribes from an Observable.
 */
public class SubscribeUnsubscribeTests {
    /**
     * A service that returns a stream of strings.
     */
    interface StringService {
        Observable<String> getStrings();
    }
    /**
     * A controller that requests strings from the {@link StringService} and logs them
     * to system out as they are received.
     */
    class StringLoggingController {
        private StringService stringService;
        private Disposable stringSubscriptionDisposable;
        public StringLoggingController(StringService stringService) {
            this.stringService = stringService;
        }
        /**
         * Causese the controller to begin strings request and logging.
         */
        public void start() {
            stringSubscriptionDisposable = stringService.getStrings()
                    .subscribe(string -> System.out.print(string));
        }
        public void stop() {
            if (stringSubscriptionDisposable != null) {
                if (!stringSubscriptionDisposable.isDisposed()) {
                    stringSubscriptionDisposable.dispose();
                    stringSubscriptionDisposable = null;
                }
            }
        }
    }
    /**
     * A {@link StringService} that can report whether {@link StringService#getStrings()}
     * has observers.
     */
    class ReportIsSubscribedStringService implements StringService {
        private PublishSubject<String> publishSubject = PublishSubject.create();
        public Observable<String> getStrings() {
            return publishSubject;
        }
        /**
         * @return true if the {@link #getStrings()} observable has observers.
         */
        public boolean stringsAreBeingObserved() {
            return publishSubject.hasObservers();
        }
    }
    /**
     * Verifies that the {@link StringLoggingController} is subscribing to the service.
     */
    @Test
    public void stringsLoggingControllerSubscribesToStringService() {
        ReportIsSubscribedStringService service = new ReportIsSubscribedStringService();
        StringLoggingController controller = new StringLoggingController(service);
        controller.start();
        assertTrue(service.stringsAreBeingObserved());
    }
    /**
     * Verifies that the {@link StringLoggingController} is unsubscribing from the service.
     */
    @Test
    public void stringsLoggingControllerUnsubscribesFromStringService() {
        ReportIsSubscribedStringService service = new ReportIsSubscribedStringService();
        StringLoggingController controller = new StringLoggingController(service);
        controller.start();
        controller.stop();
        assertFalse(service.stringsAreBeingObserved());
    }
}

——edit——我之前写过,我无法测试退订功能。我确实想出了测试的方法。结果我的测试失败了,因为被测试的代码没有正确地取消订阅(哈-测试工作,想想看)。我已经更新了上面的代码,以说明测试订阅和取消订阅。

我今天花了几个小时才意识到这是个愚蠢的错误。如果您正在使用PowerMockito,请检查您的@PrepareForTest。

@PrepareForTest({Observable.class})

也不要忘记嘲笑它。@before:

PowerMockito.mockStatic(Observable.class);

我希望它能有所帮助。谢谢你

相关内容

  • 没有找到相关文章

最新更新