Skip to content

Commit

Permalink
Merge pull request #518 from arkivanov/add-Completable-testAwait
Browse files Browse the repository at this point in the history
Add Completable.testAwait() testing function
  • Loading branch information
Arkadii Ivanov authored Aug 12, 2020
2 parents 91d9bd0 + 3d5f3d7 commit a1c4f1a
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 0 deletions.
5 changes: 5 additions & 0 deletions reaktive-testing/api/reaktive-testing.api
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ public final class com/badoo/reaktive/test/single/DefaultSingleObserver$DefaultI
public static fun onSuccess (Lcom/badoo/reaktive/test/single/DefaultSingleObserver;Ljava/lang/Object;)V
}

public final class com/badoo/reaktive/test/single/TestAwaitKt {
public static final fun testAwait (Lcom/badoo/reaktive/single/Single;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun testAwait$default (Lcom/badoo/reaktive/single/Single;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public final class com/badoo/reaktive/test/single/TestSingle : com/badoo/reaktive/test/base/TestSource, com/badoo/reaktive/single/Single, com/badoo/reaktive/single/SingleCallbacks {
public fun <init> ()V
public fun <init> (Z)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.completable.blockingAwait
import com.badoo.reaktive.single.Single

/**
* This method is used when you need to wait for an asynchronous operation to finish
* and you can't use or don't want to use the [TestScheduler][com.badoo.reaktive.test.scheduler.TestScheduler].
*
* It is JavaScript friendly, it returns `Promise` which, when returned from a test method,
* causes the test to wait for completion. In all other targets [Completable.blockingAwait()][blockingAwait] is used.
*
* Please note the following factors:
* - The [mainScheduler][com.badoo.reaktive.scheduler.mainScheduler] is not available in
* Android unit tests and will crash if used;
* - Darwin (Apple) tests are executed on the Main thread and so using the
* [mainScheduler][com.badoo.reaktive.scheduler.mainScheduler] from this method will cause dead lock.
*
* To avoid the problems above use [overrideSchedulers][com.badoo.reaktive.scheduler.overrideSchedulers]
* to replace schedulers with [TestScheduler][com.badoo.reaktive.test.scheduler.TestScheduler] or
* with [TrampolineScheduler][com.badoo.reaktive.scheduler.TrampolineScheduler].
*
* Usage example:
* ```
* class MyLogic {
* fun div(a: Int, b: Int): Single<Int> =
* singleFromFunction { a / b }
* .subscribeOn(computationScheduler)
* }
*
* class MyLogicTest {
* @Test
* fun returns_2_WHEN_div_6_by_3() =
* MyLogic()
* .div(6, 3)
* .testAwait { assertEquals(2, it) }
*
* @Test
* fun throws_ArithmeticException_WHEN_div_by_0() =
* MyLogic()
* .div(6, 0)
* .testAwait(assertError = { assertTrue(it is ArithmeticException) }, assertSuccess = { fail("Did not throw") })
* }
* ```
*
* @receiver a [Single] for which the test should wait before completing
* @param assertError when provided, it will be called in case of [Single] error and
* the test will fail only when this callback throws an exception.
* This gives an opportunity to assert the error.
* @param assertSuccess when provided, it will be called in case of [Single] success.
* This gives an opportunity to assert the result.
*/
expect fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)? = null, assertSuccess: (T) -> Unit = {})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.single.singleOf
import com.badoo.reaktive.single.singleOfError
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertSame

class TestAwaitTest {

@Test
fun succeeds_WHEN_upstream_succeeded_and_no_assertSuccess() =
singleOf(1)
.testAwait()

@Test
fun succeeds_WHEN_upstream_succeeded_and_assertSuccess_did_not_throw() =
singleOf(1)
.testAwait(assertSuccess = { assertEquals(1, it) })

@Test
fun succeeds_WHEN_upstream_failed_and_assertError_did_not_throw() {
val error = Exception()

return singleOfError<Nothing>(error)
.testAwait(assertError = { assertSame(error, it) })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.single.Single
import com.badoo.reaktive.single.asPromise
import com.badoo.reaktive.single.doOnBeforeSuccess
import com.badoo.reaktive.single.map
import com.badoo.reaktive.single.onErrorReturn

actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSuccess: (T) -> Unit): dynamic =
if (assertError == null) {
doOnBeforeSuccess(assertSuccess)
.asPromise()
} else {
map { TestAwaitResult.Success(it) }
.onErrorReturn { TestAwaitResult.Error(it) }
.doOnBeforeSuccess { result ->
when (result) {
is TestAwaitResult.Success -> assertSuccess(result.value)
is TestAwaitResult.Error -> assertError(result.error)
}
}
.asPromise()
}

private sealed class TestAwaitResult<out T> {
class Success<out T>(val value: T) : TestAwaitResult<T>()
class Error(val error: Throwable) : TestAwaitResult<Nothing>()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.badoo.reaktive.test.single

import com.badoo.reaktive.single.Single
import com.badoo.reaktive.single.blockingGet

actual fun <T> Single<T>.testAwait(assertError: ((Throwable) -> Unit)?, assertSuccess: (T) -> Unit) {
if (assertError == null) {
assertSuccess(blockingGet())
} else {
val result =
try {
blockingGet()
} catch (e: Throwable) {
assertError(e)
return
}

assertSuccess(result)
}
}

0 comments on commit a1c4f1a

Please sign in to comment.