Skip to content

TITE

A Kotlin DSL for gorgeous RxJava2 tests

Motivation

RxJava2 gives us a handy testing API : besides TestSubscriber and TestObserver, you also have a built-in test() API method available for every available reactive type, that shortcuts the retrieval of a TestObserver or TestSubscriber instance and streamlines your testing flow.

val letters = Observable.just("A","B","C")

letters
    .test()
    .assertValueCount(3)
    .assertComplete()

Both TestSubscriber and TestObserver assertions let you get your tests done; but after using these APIs for a while, you may figure out they are not perfect ...

Nevertheless, Kotlin empowers developers with a new world of possibilities, including a new field of DSL grammars using language features like infix notation for functions representations, lambdas extensions over instance types and others.

With this in mind, Tite was born. It aims to apply some grammar over TestSubscriber and TestObserver APIs while improving these APIs discoverability as well.

Source Code

Check it on Github

Setup

For now, Tite is available through Jitpack. To add it into your project :

  • Setup Jitpack as a Maven repository
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
  • Add this library to your dependencies. For an Android project
dependencies {
    implementation 'com.github.ubiratansoares.tite:tite:$version'
}

Check this project releases for the latest version.

This library will be available at Maven Central soon, I`m looking for some community feedback.

DSL Design

Tite DSL assumes that intentions for testing some reactive-type are grouped, under the following DSL blocks

Conditions before performing verifications

val target = Observable.range(1, 5)

given(target) {
    beforeChecksAwait {
        untilEmissions reach 2 // will ignore first two items
    }
}

Verifying emmited values

val numbers = Observable.just(1, 2, 3)

given(numbers) {
    verifyForEmissions {
        items match sequenceOf(1, 2, 3)
    }
}

Verifying signaled error

val expectedReason = IllegalStateException("Ouch!")
val broken = Flowable.error<Any>(reason)

given(broken) {
    verifyWhenError {
        fails byError expectedReason
    }
}

Verifying lifecycle of a sequence

val neverStarts = Completable.never()

given(neverStarts) {
    assertThatSequence {
        should notBe terminated
    }
}

Mixed verifications

Of course, you can mix all this blocks under the same unit test context, putting some structure over the fluent-and-chainable way of traditional Java

val words = Observable.just("Adenor", "Leonardo", "Bacchi")

given(words) {

    beforeChecksAwait {
        countingTime until 3.seconds
    }

    assertThatSequence {
        should be completed
        should be terminated
        should notBe broken
        should be subscribed
    }

    verifyForEmissions {
        items match sequenceOf("Adenor", "Leonardo", "Bacchi")
        firstItem shouldBe "Adenor"
        never emmits "Parreira"
        never emmits "Felipão"
    }
}

If you want to learn all convered RxJava2 testing APIs without exploring the DSL itself, please, refer to this DSL unit tests .

Building

In order to hack-and-mess with this library, we recommend

  • IntellijIDEA with Kotlin plugin 1.3.x or newer

This library is builded with Gradle. The IDE should integrate seamlessly with this project via the default Gradle wrapper.

Is this library used by someone / somewhere ?

Yes. At Stone we are using it extensively into some new products (to be launched soon! 🚀), but this library concept (and practical field validation) is older than those products, mine own, and I decided to open-source it right now.

Further Work

If you have an idea for this library, or question, please file an issue for it!

In the short term roadmap we have

  • Publish it to Maven Central
  • Cover 100% of RxJava testing APIs with DSL
  • Thinking about TestScheduler DSLs as well

License

This library is released under the MIT license