Skip to content

Instantly share code, notes, and snippets.

@GuilhE
Last active February 19, 2020 11:28
Show Gist options
  • Select an option

  • Save GuilhE/18afc4d510e245fba39c8917279d36ad to your computer and use it in GitHub Desktop.

Select an option

Save GuilhE/18afc4d510e245fba39c8917279d36ad to your computer and use it in GitHub Desktop.

Revisions

  1. GuilhE revised this gist Feb 19, 2020. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions OperatorExtensionsTest.kt
    Original file line number Diff line number Diff line change
    @@ -96,4 +96,15 @@ class OperatorExtensionsTest {
    }
    assertThat(timesReturned).isEqualTo(3)
    }

    @Test
    @ExperimentalCoroutinesApi
    fun `When throttleClick is used, Then all supersonic clicks will be avoided, useful for UI`() {
    var timesReturned = 0
    testDispatcher.runBlockingTest {
    val clickFx = throttleClick( this, clickAction = { timesReturned++ })
    repeat(100) { clickFx(Unit) }
    }
    assertThat(timesReturned).isEqualTo(1)
    }
    }
  2. GuilhE created this gist Feb 19, 2020.
    99 changes: 99 additions & 0 deletions OperatorExtensionsTest.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    import io.mockk.clearAllMocks
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.ExperimentalCoroutinesApi
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.test.TestCoroutineDispatcher
    import kotlinx.coroutines.test.resetMain
    import kotlinx.coroutines.test.runBlockingTest
    import kotlinx.coroutines.test.setMain
    import org.assertj.core.api.Assertions.assertThat
    import org.junit.jupiter.api.*
    import org.junit.jupiter.api.extension.ExtendWith

    @ExtendWith(InstantExecutorExtension::class)
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    class OperatorExtensionsTest {

    //Documentation is your friend: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/
    @ExperimentalCoroutinesApi
    private val testDispatcher = TestCoroutineDispatcher()

    @BeforeAll
    @ExperimentalCoroutinesApi
    fun setupDispatchers() {
    Dispatchers.setMain(testDispatcher)
    }

    @AfterAll
    @ExperimentalCoroutinesApi
    fun clearDispatchers() {
    Dispatchers.resetMain()
    testDispatcher.cleanupTestCoroutines()
    }

    @AfterEach
    fun clear() {
    clearAllMocks()
    }

    @Test
    @ExperimentalCoroutinesApi
    fun `When throttleFirst is called, Then it will emmit the first item and skip all the following emissions until a certain time interval is respected`() {
    var timesReturned = 0
    lateinit var throttleFirstFx: (Unit) -> Unit

    testDispatcher.runBlockingTest {
    throttleFirstFx = throttleFirst(1_000, this, action = { timesReturned++ })
    repeat(3) { throttleFirstFx(Unit) } //only one emission will hapen
    assertThat(timesReturned).isEqualTo(1)

    repeat(3) {
    delay(1_000)
    throttleFirstFx(Unit) //3 emissions
    }
    }
    assertThat(timesReturned).isEqualTo(4) //(1+3)
    }

    @Test
    @ExperimentalCoroutinesApi
    fun `When throttleLatest is called, Then it returns the latest data after a time interval without emissions`() {
    var valueReturned = 0
    lateinit var throttleLatestFx: (Int) -> Unit

    testDispatcher.runBlockingTest {
    throttleLatestFx = throttleLatest(500, this, action = { value -> valueReturned = value })
    throttleLatestFx(1)
    throttleLatestFx(2)
    throttleLatestFx(3)
    assertThat(valueReturned).isEqualTo(0) //nothing changed so far, we didn't respect the 500ms interval of emission, yet...
    delay(500) //Note that without runBlockingTest 520ms is the minimum precision
    assertThat(valueReturned).isEqualTo(3) //now that we have and the last emitted was throttleLatestFx(3), valueReturned will be 3
    throttleLatestFx(4)
    }
    assertThat(valueReturned).isEqualTo(4) //the runBlocking will wait until completion so valueReturned will be 4.
    }

    @Test
    @ExperimentalCoroutinesApi
    fun `When debounce is called it, Then returns only if there's no new data emission for a desired time interval`() {
    var timesReturned = 0
    val action: (Unit) -> Unit = { timesReturned++ }
    lateinit var debounceFx: (Unit) -> Unit

    testDispatcher.runBlockingTest {
    debounceFx = debounce(500, this, action = action)
    repeat(2) {
    debounceFx(Unit)
    }
    delay(600) //now that we've waited at least >500ms, let's emit the latest call, thus timesReturned = 1
    assertThat(timesReturned).isEqualTo(1)

    repeat(2) {
    debounceFx(Unit)
    delay(600) //each cycle we wait 600ms, all emissions will be fired, thus timesReturned = (1+2)
    }
    }
    assertThat(timesReturned).isEqualTo(3)
    }
    }