Skip to content

Commit

Permalink
Fix broken tests when run async & setup Hilt DI for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Iliyan Germanov committed Nov 21, 2021
1 parent dafe01d commit 2c1403d
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 29 deletions.
11 changes: 9 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ plugins {

android {
compileSdk = Libs.Project.compileSdkVersion
buildToolsVersion = Libs.Project.buildToolsVersion

defaultConfig {
applicationId = Libs.Project.applicationId
Expand All @@ -21,7 +20,7 @@ android {
versionCode = Libs.Project.versionCode
versionName = Libs.Project.versionName

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner = "com.ivy.wallet.HiltTestRunner"

kapt {
arguments {
Expand Down Expand Up @@ -206,4 +205,12 @@ dependencies {
//THIS IS NOT RIGHT: Implementation for IdlingResource access on both Debug & Release
//Without having this dependency "lintRelease" fails
implementation(Libs.Testing.Compose.junit4)
//--------------------------------------

//Hilt Testing setup
androidTestImplementation(Libs.Testing.Hilt.daggerHilt)
kaptAndroidTest(Libs.Testing.Hilt.kaptHilt)
implementation(Libs.Testing.Hilt.androidTestRunner)
implementation(Libs.Testing.Hilt.androidWork)
//-------------------------------------------------------------------
}
14 changes: 14 additions & 0 deletions app/src/androidTest/java/com/ivy/wallet/HiltTestRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ivy.wallet

import android.app.Application
import android.content.Context
import androidx.test.runner.AndroidJUnitRunner
import dagger.hilt.android.testing.HiltTestApplication

// A custom runner to set up the instrumented application class for tests.
class HiltTestRunner : AndroidJUnitRunner() {

override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.performClick
import com.ivy.wallet.compose.helpers.AmountInput
import com.ivy.wallet.compose.helpers.OnboardingFlow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Test

@HiltAndroidTest
class BasicOperationsTest : IvyComposeTest() {

@ExperimentalCoroutinesApi
@Test
fun OnboardAndAdjustBalance() = runBlocking {
fun contextLoads() {
}

@Test
fun OnboardAndAdjustBalance() {
val onboarding = OnboardingFlow(composeTestRule)
val amountInput = AmountInput(composeTestRule)

Expand All @@ -34,6 +37,8 @@ class BasicOperationsTest : IvyComposeTest() {
.performClick()

amountInput.pressNumber(1)

composeTestRule.printTree()
// amountInput.pressNumber(0)
// amountInput.pressNumber(2)
// amountInput.pressNumber(5)
Expand Down
45 changes: 37 additions & 8 deletions app/src/androidTest/java/com/ivy/wallet/compose/IvyComposeTest.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,56 @@
package com.ivy.wallet.compose

import android.content.Context
import android.util.Log
import androidx.compose.ui.test.IdlingResource
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.platform.app.InstrumentationRegistry
import androidx.work.Configuration
import androidx.work.impl.utils.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
import com.ivy.wallet.base.TestIdlingResource
import com.ivy.wallet.base.TestingContext
import com.ivy.wallet.persistence.IvyRoomDatabase
import com.ivy.wallet.persistence.SharedPrefs
import com.ivy.wallet.ui.IvyActivity
import com.ivy.wallet.ui.IvyContext
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import javax.inject.Inject

@HiltAndroidTest
abstract class IvyComposeTest {
//TODO: Setup Hilt, too
//https://developer.android.com/training/dependency-injection/hilt-testing
@get:Rule
var hiltRule = HiltAndroidRule(this)

@get:Rule
val composeTestRule = createAndroidComposeRule<IvyActivity>()
// use createAndroidComposeRule<YourActivity>() if you need access to an activity

private var idlingResource: IdlingResource? = null

@Inject
lateinit var ivyContext: IvyContext

@Before
fun setUp() {
TestIdlingResource.reset()
idlingResource = TestIdlingResource.idlingResource
composeTestRule.registerIdlingResource(idlingResource!!)

val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
.build()
WorkManagerTestInitHelper.initializeTestWorkManager(context(), config)
hiltRule.inject()

TestingContext.inTest = true

resetApp()
}

@After
Expand All @@ -37,23 +60,29 @@ abstract class IvyComposeTest {
}

TestingContext.inTest = false

resetApp()
}

protected fun resetApp() {
private fun resetApp() {
clearSharedPrefs()
deleteDatabase()
resetIvyContext()
}

private fun clearSharedPrefs() {
SharedPrefs(context()).removeAll()
}

protected fun clearSharedPrefs() {
SharedPrefs(targetContext()).removeAll()
private fun deleteDatabase() {
IvyRoomDatabase.create(context()).reset()
}

protected fun deleteDatabase() {
targetContext().deleteDatabase(IvyRoomDatabase.DB_NAME)
private fun resetIvyContext() {
ivyContext.reset()
}

private fun targetContext(): Context {
private fun context(): Context {
return InstrumentationRegistry.getInstrumentation().targetContext
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.hasText
import com.ivy.wallet.compose.helpers.MainBottomBar
import com.ivy.wallet.compose.helpers.OnboardingFlow
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Test

@HiltAndroidTest
class OnboardingTest : IvyComposeTest() {

@Test
fun contextLoads() {
}

@Test
fun OnboardingShortestPath() {
val onboarding = OnboardingFlow(composeTestRule)
Expand All @@ -24,6 +30,4 @@ class OnboardingTest : IvyComposeTest() {
composeTestRule.onNode(hasText("Cash"))
.assertIsDisplayed()
}


}
4 changes: 4 additions & 0 deletions app/src/main/java/com/ivy/wallet/base/ComposeTesting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ object TestIdlingResource {
throw IllegalStateException("TestIdlingResource counter is corrupted! value = ${counter.get()}")
}
}

fun reset() {
counter.set(0)
}
}
1 change: 0 additions & 1 deletion app/src/main/java/com/ivy/wallet/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ object AppModule {
): IvyRoomDatabase {
return IvyRoomDatabase.create(
applicationContext = appContext,
gson = Gson()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import com.google.gson.Gson
import com.ivy.wallet.model.entity.*
import com.ivy.wallet.persistence.dao.*
import com.ivy.wallet.persistence.migration.*
Expand Down Expand Up @@ -43,8 +42,7 @@ abstract class IvyRoomDatabase : RoomDatabase() {
companion object {
const val DB_NAME = "ivywallet.db"

fun create(applicationContext: Context, gson: Gson): IvyRoomDatabase {
RoomTypeConverters.gson = gson
fun create(applicationContext: Context): IvyRoomDatabase {
return Room
.databaseBuilder(
applicationContext,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.ivy.wallet.persistence

import androidx.room.TypeConverter
import com.google.gson.Gson
import com.ivy.wallet.base.epochMilliToDateTime
import com.ivy.wallet.base.toEpochMilli
import com.ivy.wallet.model.AuthProviderType
Expand All @@ -13,11 +12,6 @@ import java.util.*

@SuppressWarnings("unused")
class RoomTypeConverters {

companion object {
lateinit var gson: Gson
}

@TypeConverter
fun saveDate(localDateTime: LocalDateTime?): Long? = localDateTime?.toEpochMilli()

Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/com/ivy/wallet/ui/IvyContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,14 @@ class IvyContext {
fun switchTheme(theme: Theme) {
this.theme = theme
}

//Testing --------------------------------------------------------------------------------------
fun reset() {
mainTab = MainTab.HOME
startDayOfMonth = 1
currentScreen = null
isPremium = false
transactionsListState = null
resetBackStack()
}
}
14 changes: 11 additions & 3 deletions buildSrc/src/main/java/com/ivy/wallet/buildsrc/dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ object Libs {
const val versionCode = 86

//Compile SDK & Build Tools
const val compileSdkVersion = 30
const val buildToolsVersion = "30.0.3"
const val compileSdkVersion = 31

//App
const val applicationId = "com.ivy.wallet"
Expand All @@ -52,7 +51,7 @@ object Libs {
const val coreKtx = "androidx.core:core-ktx:1.5.0"

//URL: https://developer.android.com/jetpack/androidx/releases/work
internal const val workVersion = "2.6.0-beta01"
internal const val workVersion = "2.7.1"
const val workRuntime = "androidx.work:work-runtime-ktx:$workVersion"

const val biometrics = "androidx.biometric:biometric:1.1.0"
Expand Down Expand Up @@ -215,5 +214,14 @@ object Libs {
const val composeTestRule =
"androidx.compose.ui:ui-test-manifest:${AndroidX.Compose.version}"
}

object Hilt {
//https://developer.android.com/training/dependency-injection/hilt-testing

val daggerHilt = "com.google.dagger:hilt-android-testing:${Libs.Hilt.version}"
val kaptHilt = "com.google.dagger:hilt-android-compiler:${Libs.Hilt.version}"
val androidTestRunner = "androidx.test:runner:1.4.0"
val androidWork = "androidx.work:work-testing:${Libs.AndroidX.workVersion}"
}
}
}

0 comments on commit 2c1403d

Please sign in to comment.