Java 单元测试-验证是否订阅了Observable

Java 单元测试-验证是否订阅了Observable,java,unit-testing,mockito,rx-java,observable,Java,Unit Testing,Mockito,Rx Java,Observable,我有这样的java代码 mDataManager.getObservable("hello").subscribe( subscriber ); 我想验证以下可观察到的是.subscribe() 我试图模拟getObservable()和验证 Observable<Response> res = mock(Observable.class); when(mDataManager.getObservable("hello")).thenReturn(res); verify(

我有这样的java代码

 mDataManager.getObservable("hello").subscribe( subscriber );
我想
验证
以下可观察到的是
.subscribe()

我试图模拟
getObservable()
验证

 Observable<Response> res = mock(Observable.class);
 when(mDataManager.getObservable("hello")).thenReturn(res);
 verify(res).subscribe();
我认为这里不可能有一个可观察的
mock
,但是如果没有一个可观察的mock,我就无法进行
verify(res.subscribe()


在这种情况下有什么建议吗?

也许您可以使用
Observable.onSubscribe
方法和
RunTestOnContext
规则?
TestContext
可以为您提供一个
Async
对象,该对象仅在测试完成后终止测试。我认为,如果你将此与
Observable#doOnSubscribe
相结合,就可以实现所需的行为

但是,使用
Async
有时可能会有点混乱。在下面的示例中,如果observable从未订阅过,那么
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();
  }
}
@RunWith(VertxUnitRunner.class)
公共类订阅测试{
@统治
public RunTestOnContext vertxRule=new RunTestOnContext();
@试验
已订阅公共测试(最终测试上下文){
final Async Async=context.Async();
最终可观测的可观测=可观测的.just(“hello”).doOnSubscribe(异步::完成);
最终经理模拟=模拟(Manager.class);
when(mock.getObservable())。然后return(observable);
mock.getObservable().subscribe();
}
接口管理器{
可观察的getObservable();
}
}

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

您可以这样创建它

private TestScheduler eventsScheduler = new TestScheduler();
private TestSubject<MyEvent> eventObservable = TestSubject.create(eventsScheduler);
TestSubject还允许您确定发送事件的时间

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

我不确定我是否回答了这个问题,但我想是的

可以创建单元测试,以检查是否订阅了可观察对象。请注意,在RXJava1.x中,TestSubject支持这一点,但Subject实现可以简化这一功能。测试对象是

不要像原始海报那样试图模仿可观察对象,而是使用PublishSubject,运行业务逻辑,然后使用publish subject查看是否观察到可观察对象。下面是一些测试代码,用于验证此测试是否可行。当我运行测试时,测试通过了

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

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());
    }
}
import org.junit.Test;
导入io.reactivex.Observable;
进口io.reactivex.disposables.Disposable;
导入io.reactivex.subjects.PublishSubject;
导入静态junit.framework.Assert.assertFalse;
导入静态junit.framework.Assert.assertTrue;
/**
*测试是否有可能测试控制器是否正确地取消了对可观察对象的订阅。
*/
公共类订阅取消订阅测试{
/**
*返回字符串流的服务。
*/
接口服务{
可观察的getStrings();
}
/**
*从{@link StringService}请求字符串并记录它们的控制器
*在收到它们时进行系统输出。
*/
类StringLoggingController{
私人服务;
私人一次性使用的stringSubscriptionDisposable;
公共StringLoggingController(StringService StringService){
this.stringService=stringService;
}
/**
*使控制器开始字符串请求和日志记录。
*/
公开作废开始(){
stringSubscriptionDisposable=stringService.getStrings()
.subscribe(字符串->系统输出打印(字符串));
}
公共停车场(){
if(stringSubscriptionDisposable!=null){
如果(!stringSubscriptionDisposable.isDisposed()){
stringSubscriptionDisposable.dispose();
stringSubscriptionDisposable=null;
}
}
}
}
/**
*一个{@link StringService},可以报告{@link StringService#getStrings()}
*有观察员。
*/
类ReportIsSubscribedStringService实现StringService{
private PublishSubject PublishSubject=PublishSubject.create();
公共可观察的getStrings(){
返回出版主题;
}
/**
*@return true,如果{@link#getStrings()}可观察对象有观察者。
*/
公共布尔字符串RebeingObserved(){
返回publishSubject.hasObservators();
}
}
/**
*验证{@link StringLoggingController}是否正在订阅该服务。
*/
@试验
public void StringSloggingControllerSubscribestStringService(){
ReportIsSubscribedStringService=新的ReportIsSubscribedStringService();
StringLoggingController控制器=新的StringLoggingController(服务);
controller.start();
assertTrue(service.StringsRebeingObserved());
}
/**
*验证{@link StringLoggingController}是否正在从服务取消订阅。
*/
@试验
公共无效stringsLoggingControllerUnsubscribesFromStringService(){
ReportIsSubscribedStringService=新的ReportIsSubscribedStringService();
StringLoggingController控制器=新的StringLoggingController(服务);
controller.start();
controller.stop();
assertFalse(service.StringsRebeingObserved());
}
}
--编辑-- 我以前写过,我无法测试退订。我确实想出了测试的方法
eventObservable.onNext(new MyEvent());
eventsScheduler.triggerActions(); 
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());
    }
}
@PrepareForTest({Observable.class})
PowerMockito.mockStatic(Observable.class);