Unit Testing Fundamentals for Reactive Programming in Android (Kotlin)

Tri Nhan Nguyen
3 min readMay 4, 2020
RxKotlin

Testing overview

Generally, testing is divided into unit testing and acceptance testing. The focuses of the two types are on different parts of the program and different purposes. Since acceptance testing tests the way parts of code work together and is platform dependent, it has little to do with reactive programming. In reality, the two types are more of a spectrum. However, pure data and pure functions are the responsibility of unit testing. If the reactive architectures are done correctly, most of the written code should be pure functions, which manipulate pure data. Thus, this post will only discuss unit testing of reactive code in RxKotlin.

Unit testing basics

A unit test should test that the code does just one thing correctly under certain conditions. Ideally, it should covers all possible execution paths (or 100% code coverage) but it should not use framework (Android) classes. Unit tests work best when it is clear and descriptive to the developer. Thus, following a certain pattern can be one of the most effective things to enhance the quality of unit tests. According to Microsoft Visual Studio Docs, a common testing pattern is AAA (Arrange, Act, Assert):

  • Arrange of a unit test method initializes objects and sets the value of the data that is passed to the method under test.
  • Act invokes the method under test with the arranged parameters.
  • Assert verifies that the action of a method under test behaves as expected.

The separation of the steps helps a lot with the readability and maintainability when the test grows larger and more complicated.

Testing reactive code

Setting up

Most of the powerful tools are included in the RxJava library. One library that are extremely useful in unit testing is Mockito for mocking objects.

// app/build.gradledependencies {
...
testCompile 'org.mockito:mockito-core:3.3.+'
}

Reactive chains

Reactive chains get deterministic outputs given certain inputs. Thus, a chain should be treated as a pure function which makes it straightforward to unit test. Mockito is a helpful library for unit testing since mocking objects are more controlled and readable. However, mocking objects is not tightly related to reactive programming; therefore, it is out of the scope of this section. The section will focus on testing observables and subscribers.

Regarding unit testing, the most important tool coming from RxJava is TestObservable. There are a couple of useful functions to inspect the behaviors of observables and subscribers:

  • assertComplete(): check if complete signal is emitted
  • assertError(…): check for a specific error signal
  • assertNotTerminated(): check if no error or complete signal is emitted
  • assertValue(…): check if the correct value is emitted
  • assertValueCount(Int): check if the correct number of values are emitted

To illustrate all the techniques and tools, sortTest is created to test a sort function.

@Test
fun sortTest() {
// Arrange
val testObserver = TestObserver<List<Int>>();
var list = mutableListOf(1, 2, 0);
// Act
list.sort().subscribe(testObserver);
// Assert
testObserver.assertValueCount(1);
testObserver.assertComplete();
val sortedList = testObserver.values().get(0);
assertEquals(3, sortedList.size);
assertEquals(0, sortedList.getOrNull(0);
assertEquals(1, sortedList.getOrNull(1);
assertEquals(2, sortedList.getOrNull(2);
}

Asynchronous code

It is true that the subscriber is called asynchronously, and the list might not have been defined or initialized. However, in RxJava, if no thread changes are declared in the code, the data flows on the same thread. Thus, unless it is necessary, changing threads should be avoided. Testing asynchronous operations, operations that are time- dependent, is not discussed but it is usually only used in searching or animations which are more of details not architectural. For more information regarding asynchronous testing, thanks to Paulina, we have an awesome post here on Medium.

Thanks for your time!

Reference:

--

--