0

I'm trying to use JUnit4 in an Android project, where I also use RxAndroid/RxJava.

What I do is calling REST API from UUID generator using retrofit

UUIDApi.java just an interface for retrofit calls (now is just one)

public interface UUIDApi {

    static final String BASE_URL = "https://www.uuidgenerator.net";

    @GET("/api/version4")
    Observable<String> getUUID();
}

UUIDModel.java where retrofit is initialized and where the interface written above is implemented

public class UUIDModel implements UUIDApi{
    private Retrofit retrofit;
    private UUIDApi uuidApi;
    UUIDObserver uuidObserver = new UUIDObserver();

    public UUIDModel() {
        retrofit = new Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(new ToStringConverterFactory())
                .baseUrl(UUIDApi.BASE_URL)
                .build();
        uuidApi = retrofit.create(UUIDApi.class);
    }

    @Override
    public Observable<String> getUUID() {
        return uuidApi.getUUID();
    }

    public void generateUUID(){
        Observable<String> observable =  this.getUUID();
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(uuidObserver);
    }
}

Than I have the UUIDObserver that is just a class that implements Observer.

Note: new ToStringConverterFactory is a class I found here

Executing this code using emulator, I know for sure that it works fine. The problem is that I don't understand how to junit this code since using rxAndroid/rxJava it gets executed in another thread.

I read that:

The official way to test an observable is by using a TestSubscriber, an helper subscriber provided directly by the RxJava library.

so I tried

@Test
    public void test_uuid() throws Exception {
        UUIDApi uuidApi = new UUIDModel();
        Observable<String> observable = uuidApi.getUUID();

        TestSubscriber<String> testSubscriber = new TestSubscriber<>();
        observable.subscribe(testSubscriber);

    }

but at observable.subscribe(testSubscriber); I get the error 'cannot resolve method 'subscribe(io.reactivex.subscribers.TestSubscriber)'

What am I doing wrong? How should I cope with rxProgramming and JUnit?

Mitro
  • 1,230
  • 8
  • 32
  • 61
  • There's also a `TestObserver` - use that; `TestSubscriber` is for flowables. – Tassos Bassoukos May 22 '17 at 15:17
  • I've just found out this link that can be very useful, if you are gonna try testing https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#testing – Mitro Jun 01 '17 at 13:57

3 Answers3

2

TestSubscriber is relevant for Flowable while TestObserver is used with Observable. But for both you don't actually have to subscribe anything manually. You just use the test() method instead.

observable.test()
      .assertNoErrors()
      .assertValue(expected)
      .assertComplete();
tynn
  • 38,113
  • 8
  • 108
  • 143
1

I am testing RxJava + Retrofit like that :

First of all I am using Schedulers.trampoline() for testing purposes. Then in a basic unit test :

@Mock
ResponseBody mockResponseBody;

@Test
public void testCondition(){
    when(mService.operation()).thenReturn(Observable.just(response));

    mPresenter.handleOperation();

    verify(mView).operationResult();
}

I am testing 3 case : Success response(between 200-300),error response,fail

For testing success : response = Response.success(your_body);

For testing error : response= Response.error(any_error_code,mockResponseBody);

For testing fail : Just return Observable.error(); inside thenReturn

In this unit test we are mocking our webservice calls and it never depends on webservice so you can run your unit tests even when you offline.

But if you want to see real webservice calls you can write integration tests.

Yasin Kaçmaz
  • 6,573
  • 5
  • 40
  • 58
1

You could utilize test operator to subscribe your Observable with TestObserver, which records events and allows you to make assertions about them:

observable
    .test()
    .assertValue(...)
    .assertComplete()
    //etc

To deal with async operations in your reactive stream you could try these approaches:

  • utilize TestObserver's handy await operator, wich awaits until the TestObserver receives an onError or onComplete events.

  • provide Schedulers via dependency injection (e.g. with constructor injection), so you could substitute them in tests with Schedulers.trampoline.

  • change your async Scheduler's default implementation with one of RxJava's hook functions (e.g. RxJavaPlugins.setInitIoSchedulerHandler).

Maksim Ostrovidov
  • 10,720
  • 8
  • 42
  • 57