Skip to content
This repository was archived by the owner on Aug 16, 2023. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion coroutines-codelab/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ buildscript {
def arch_version = '2.1.0'
def appcompat_version = '1.4.1'
def constraint_layout_version = '2.1.3'
def coroutines_android_version = '1.5.2'
def coroutines_android_version = '1.6.0'
def espresso_version = '3.4.0'
def gson_version = '2.9.0'
def junit_version = '4.13.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.example.android.kotlincoroutines.fakes.MainNetworkCompletableFake
import com.example.android.kotlincoroutines.fakes.MainNetworkFake
import com.example.android.kotlincoroutines.fakes.TitleDaoFake
import com.example.android.kotlincoroutines.main.utils.MainCoroutineScopeRule
import com.example.android.kotlincoroutines.main.utils.MainCoroutineRule
import com.example.android.kotlincoroutines.main.utils.captureValues
import com.example.android.kotlincoroutines.main.utils.getValueForTest
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import okhttp3.MediaType
import okhttp3.ResponseBody
import org.junit.Before
Expand All @@ -36,32 +38,33 @@ import org.junit.runners.JUnit4
import retrofit2.HttpException
import retrofit2.Response

@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(JUnit4::class)
class MainViewModelTest {

@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

@get:Rule
val coroutineScope = MainCoroutineScopeRule()
val coroutineRule = MainCoroutineRule(UnconfinedTestDispatcher())

lateinit var subject: MainViewModel

@Before
fun setup() {
subject = MainViewModel(
TitleRepository(
MainNetworkFake("OK"),
TitleDaoFake("initial")
))
TitleRepository(
MainNetworkFake("OK"),
TitleDaoFake("initial")
))
}

@Test
fun whenMainClicked_updatesTaps() {
fun whenMainClicked_updatesTaps() = runTest {
subject.onMainViewClicked()
Truth.assertThat(subject.taps.getValueForTest()).isEqualTo("0 taps")
coroutineScope.advanceTimeBy(1000)
Truth.assertThat(subject.taps.getValueForTest()).isEqualTo("1 taps")
assertThat(subject.taps.getValueForTest()).isEqualTo("0 taps")
advanceTimeBy(1001)
assertThat(subject.taps.getValueForTest()).isEqualTo("1 taps")
}

@Test
Expand All @@ -70,14 +73,14 @@ class MainViewModelTest {
}

@Test
fun whenSuccessfulTitleLoad_itShowsAndHidesSpinner() = coroutineScope.runBlockingTest {
fun whenSuccessfulTitleLoad_itShowsAndHidesSpinner() = runTest {
val network = MainNetworkCompletableFake()

subject = MainViewModel(
TitleRepository(
network,
TitleDaoFake("title")
)
TitleRepository(
network,
TitleDaoFake("title")
)
)

subject.spinner.captureValues {
Expand All @@ -89,13 +92,13 @@ class MainViewModelTest {
}

@Test
fun whenErrorTitleReload_itShowsErrorAndHidesSpinner() = coroutineScope.runBlockingTest {
fun whenErrorTitleReload_itShowsErrorAndHidesSpinner() = runTest {
val network = MainNetworkCompletableFake()
subject = MainViewModel(
TitleRepository(
network,
TitleDaoFake("title")
)
TitleRepository(
network,
TitleDaoFake("title")
)
)

subject.spinner.captureValues {
Expand All @@ -108,13 +111,13 @@ class MainViewModelTest {
}

@Test
fun whenErrorTitleReload_itShowsErrorText() = coroutineScope.runBlockingTest {
fun whenErrorTitleReload_itShowsErrorText() = runTest {
val network = MainNetworkCompletableFake()
subject = MainViewModel(
TitleRepository(
network,
TitleDaoFake("title")
)
TitleRepository(
network,
TitleDaoFake("title")
)
)

subject.onMainViewClicked()
Expand All @@ -125,24 +128,24 @@ class MainViewModelTest {
}

@Test
fun whenMainViewClicked_titleIsRefreshed() = coroutineScope.runBlockingTest {
fun whenMainViewClicked_titleIsRefreshed() = runTest {
val titleDao = TitleDaoFake("title")
subject = MainViewModel(
TitleRepository(
MainNetworkFake("OK"),
titleDao
)
TitleRepository(
MainNetworkFake("OK"),
titleDao
)
)
subject.onMainViewClicked()
assertThat(titleDao.nextInsertedOrNull()).isEqualTo("OK")
}

private fun makeErrorResult(result: String): HttpException {
return HttpException(Response.error<String>(
500,
ResponseBody.create(
MediaType.get("application/json"),
"\"$result\"")
500,
ResponseBody.create(
MediaType.get("application/json"),
"\"$result\"")
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,37 @@ import com.example.android.kotlincoroutines.fakes.MainNetworkCompletableFake
import com.example.android.kotlincoroutines.fakes.MainNetworkFake
import com.example.android.kotlincoroutines.fakes.TitleDaoFake
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test

@OptIn(ExperimentalCoroutinesApi::class)
class TitleRepositoryTest {

@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

@Test
fun whenRefreshTitleSuccess_insertsRows() = runBlockingTest {
fun whenRefreshTitleSuccess_insertsRows() = runTest {
val titleDao = TitleDaoFake("title")
val subject = TitleRepository(
MainNetworkFake("OK"),
titleDao
MainNetworkFake("OK"),
titleDao
)

subject.refreshTitle()
assertThat(titleDao.nextInsertedOrNull()).isEqualTo("OK")
}

@Test(expected = TitleRefreshError::class)
fun whenRefreshTitleTimeout_throws() = runBlockingTest {
fun whenRefreshTitleTimeout_throws() = runTest {
val network = MainNetworkCompletableFake()
val subject = TitleRepository(
network,
TitleDaoFake("title")
network,
TitleDaoFake("title")
)

launch {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.android.kotlincoroutines.main.utils

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain
import org.junit.rules.TestWatcher
import org.junit.runner.Description

/**
* MainCoroutineRule installs a TestDispatcher for Dispatchers.Main.
*
* When using MainCoroutineRule, you should use runTest to contain your tests:
*
* ```
* @Test
* fun usingRunTest() = runTest {
* aTestCoroutine()
* }
* ```
*
* @param dispatcher if provided, this [TestDispatcher] will be used.
*/
@ExperimentalCoroutinesApi
class MainCoroutineRule(val dispatcher: TestDispatcher = StandardTestDispatcher()) :
TestWatcher() {

override fun starting(description: Description?) {
super.starting(description)
// All injected dispatchers in a test should be TestDispatchers that share the same
// TestScheduler (available as dispatcher.scheduler). All TestDispatchers created after
// the Main dispatcher has been replaced will automatically share its scheduler.
Dispatchers.setMain(dispatcher)

// If you need to create and inject test dispatchers before this happens, create a
// TestScheduler yourself, and pass it to all test dispatchers explicitly.
}

override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ package com.example.android.kotlincoroutines.main
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.example.android.kotlincoroutines.fakes.MainNetworkFake
import com.example.android.kotlincoroutines.fakes.TitleDaoFake
import com.example.android.kotlincoroutines.main.utils.MainCoroutineScopeRule
import com.example.android.kotlincoroutines.main.utils.MainCoroutineRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@OptIn(ExperimentalCoroutinesApi::class)
class MainViewModelTest {
@get:Rule
val coroutineScope = MainCoroutineScopeRule()
val coroutineRule = MainCoroutineRule()

@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

Expand All @@ -35,14 +38,14 @@ class MainViewModelTest {
@Before
fun setup() {
subject = MainViewModel(
TitleRepository(
MainNetworkFake("OK"),
TitleDaoFake("initial")
))
TitleRepository(
MainNetworkFake("OK"),
TitleDaoFake("initial")
))
}

@Test
fun whenMainClicked_updatesTaps() {
// TODO: Write this
}
}
}
Loading