Skip to content

Commit c45ee37

Browse files
committed
Integrated database module.
Integrated test unit and integration test.
1 parent e031b79 commit c45ee37

File tree

19 files changed

+513
-18
lines changed

19 files changed

+513
-18
lines changed

app/build.gradle.kts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ android {
1717
versionCode = 1
1818
versionName = "1.0"
1919

20-
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
20+
testInstrumentationRunner = "ytemplate.android.HiltTestRunner"
2121
vectorDrawables {
2222
useSupportLibrary = true
2323
}
@@ -53,15 +53,30 @@ dependencies {
5353
val testLib = ytemplate.android.build.TestLib
5454
implementation (androidLib.CORE_KTX)
5555
implementation (androidLib.RUNTIME_KTX)
56+
5657
implementation (androidLib.COMPOSE_ACTIVITY)
5758
implementation (androidLib.COMPOSE_UI)
5859
implementation (androidLib.COMPOSE_PREVIEW)
5960
implementation (androidLib.COMPOSE_MATERIAL)
6061
implementation(androidLib.COMPOSE_VIEW_MODEL)
6162
implementation(androidLib.COMPOSE_NAV)
63+
androidTestImplementation(androidLib.COMPOSE_NAV_TEST)
6264
implementation(androidLib.HILT_ANDROID)
6365
kapt(androidLib.HILT_COMPILER)
6466
implementation(androidLib.HILT_NAV_COMPOSE)
67+
//Hilt instrumented test
68+
androidTestImplementation(androidLib.HILT_TEST)
69+
kaptAndroidTest(androidLib.HILT_COMPILER)
70+
71+
//coroutine
72+
implementation(androidLib.COROUTINE)
73+
testImplementation(androidLib.COROUTINE_TEST)
74+
//Room
75+
implementation(androidLib.ROOM_RUNTIME)
76+
annotationProcessor(androidLib.ROOM_COMPILER)
77+
kapt(androidLib.ROOM_COMPILER)
78+
implementation(androidLib.ROOM_KTX)
79+
testImplementation(androidLib.ROOM_TEST)
6580

6681
testImplementation (testLib.JUNIT)
6782
androidTestImplementation (androidLib.JUNIT_ANDROID)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package ytemplate.android
2+
3+
import android.app.Application
4+
import android.content.Context
5+
import androidx.test.runner.AndroidJUnitRunner
6+
import dagger.hilt.android.testing.HiltTestApplication
7+
8+
class HiltTestRunner : AndroidJUnitRunner() {
9+
override fun newApplication(
10+
cl: ClassLoader?,
11+
className: String?,
12+
context: Context?
13+
): Application {
14+
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
15+
}
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package ytemplate.android
2+
3+
import dagger.hilt.android.testing.HiltAndroidRule
4+
import dagger.hilt.android.testing.HiltAndroidTest
5+
import org.junit.Rule
6+
7+
@HiltAndroidTest
8+
class MainActivityTest {
9+
@get:Rule
10+
var hiltRule = HiltAndroidRule(this)
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package ytemplate.android.data
2+
3+
import dagger.Binds
4+
import dagger.Module
5+
import dagger.hilt.components.SingletonComponent
6+
import dagger.hilt.testing.TestInstallIn
7+
import ytemplate.android.data.di.DataModule
8+
import ytemplate.android.data.di.FakeMyModelRepository
9+
10+
@Module
11+
@TestInstallIn(
12+
components = [SingletonComponent::class],
13+
replaces = [DataModule::class]
14+
)
15+
interface TestDataModule {
16+
@Binds
17+
fun bindMyModelRepository(fakeMyModelRepository: FakeMyModelRepository): MyModelRepository
18+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package ytemplate.android.database
2+
3+
import android.content.Context
4+
import androidx.room.Room
5+
import androidx.test.core.app.ApplicationProvider
6+
import androidx.test.ext.junit.runners.AndroidJUnit4
7+
import kotlinx.coroutines.ExperimentalCoroutinesApi
8+
import kotlinx.coroutines.flow.first
9+
import kotlinx.coroutines.test.runTest
10+
import org.junit.After
11+
import org.junit.Assert
12+
import org.junit.Before
13+
import org.junit.Test
14+
import org.junit.runner.RunWith
15+
import ytemplate.android.database.model.MyModel
16+
import ytemplate.android.database.model.MyModelDao
17+
18+
@RunWith(AndroidJUnit4::class)
19+
class AppDataBaseTest {
20+
private lateinit var myModelDao: MyModelDao
21+
private lateinit var database: AppDataBase
22+
23+
@Before
24+
fun setUp() {
25+
val context = ApplicationProvider.getApplicationContext<Context>()
26+
database = Room.inMemoryDatabaseBuilder(context, AppDataBase::class.java).build()
27+
myModelDao = database.myModelDao()
28+
}
29+
30+
@OptIn(ExperimentalCoroutinesApi::class)
31+
@Test
32+
@kotlin.jvm.Throws(Exception::class)
33+
fun testWriteMyModel() = runTest {
34+
val myModel = MyModel(name = "Test")
35+
myModelDao.insert(myModel)
36+
val data = myModelDao.getMyModels().first().first()
37+
Assert.assertEquals(myModel.name, data.name)
38+
}
39+
40+
@After
41+
@kotlin.jvm.Throws(Exception::class)
42+
fun tearDown() {
43+
database.close()
44+
}
45+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package ytemplate.android.ui
2+
3+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
4+
import dagger.hilt.android.testing.HiltAndroidRule
5+
import dagger.hilt.android.testing.HiltAndroidTest
6+
import org.junit.Rule
7+
import ytemplate.android.MainActivity
8+
9+
@HiltAndroidTest
10+
class MainNavigationKtTest{
11+
@get:Rule(order = 0)
12+
var hiltRule = HiltAndroidRule(this)
13+
@get:Rule(order = 1)
14+
val composeTestRule = createAndroidComposeRule<MainActivity>()
15+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package ytemplate.android.ui.mymodel
2+
3+
import androidx.compose.ui.test.assertIsDisplayed
4+
import androidx.compose.ui.test.junit4.createComposeRule
5+
import androidx.compose.ui.test.onNodeWithTag
6+
import androidx.compose.ui.test.onNodeWithText
7+
import androidx.test.ext.junit.runners.AndroidJUnit4
8+
import org.junit.Before
9+
import org.junit.Rule
10+
import org.junit.Test
11+
import org.junit.runner.RunWith
12+
import ytemplate.android.data.di.FakeMyModelRepository
13+
import ytemplate.android.ui.theme.YTemplateTheme
14+
15+
@RunWith(AndroidJUnit4::class)
16+
class MyModelScreenKtTest {
17+
18+
@get:Rule
19+
val composeRule = createComposeRule()
20+
lateinit var viewModel: MyModelViewModel
21+
@Before
22+
fun setUp() {
23+
viewModel = MyModelViewModel(FakeMyModelRepository())
24+
}
25+
26+
@Test
27+
fun testAddButton() {
28+
composeRule.setContent {
29+
YTemplateTheme {
30+
MyModelScreen(viewModel)
31+
}
32+
}
33+
composeRule.onNodeWithTag("add_button").assertIsDisplayed()
34+
composeRule.onNodeWithTag("name_field").assertIsDisplayed()
35+
composeRule.onNodeWithText("test1").assertIsDisplayed()
36+
}
37+
}

app/src/main/java/ytemplate/android/MainActivity.kt

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ import androidx.activity.compose.setContent
66
import androidx.compose.foundation.layout.fillMaxSize
77
import androidx.compose.material.MaterialTheme
88
import androidx.compose.material.Surface
9-
import androidx.compose.material.Text
10-
import androidx.compose.runtime.Composable
119
import androidx.compose.ui.Modifier
12-
import androidx.compose.ui.tooling.preview.Preview
1310
import dagger.hilt.android.AndroidEntryPoint
11+
import ytemplate.android.ui.MainNavigation
1412
import ytemplate.android.ui.theme.YTemplateTheme
1513

1614
@AndroidEntryPoint
@@ -24,22 +22,9 @@ class MainActivity : ComponentActivity() {
2422
modifier = Modifier.fillMaxSize(),
2523
color = MaterialTheme.colors.background
2624
) {
27-
Greeting("Android")
25+
MainNavigation()
2826
}
2927
}
3028
}
3129
}
3230
}
33-
34-
@Composable
35-
fun Greeting(name: String) {
36-
Text(text = "Hello $name!")
37-
}
38-
39-
@Preview(showBackground = true)
40-
@Composable
41-
fun DefaultPreview() {
42-
YTemplateTheme {
43-
Greeting("Android")
44-
}
45-
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package ytemplate.android.data
2+
3+
import kotlinx.coroutines.flow.Flow
4+
import kotlinx.coroutines.flow.map
5+
import ytemplate.android.database.model.MyModel
6+
import ytemplate.android.database.model.MyModelDao
7+
import javax.inject.Inject
8+
9+
interface MyModelRepository {
10+
11+
val myModel: Flow<List<String>>
12+
suspend fun add(name: String)
13+
}
14+
15+
class MyModelRepositoryImpl @Inject constructor(private val myModelDao: MyModelDao) :
16+
MyModelRepository {
17+
override val myModel: Flow<List<String>>
18+
get() = myModelDao.getMyModels().map { items-> items.map { it.name } }
19+
20+
override suspend fun add(name: String) {
21+
myModelDao.insert(MyModel(name = name))
22+
}
23+
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package ytemplate.android.data.di
2+
3+
import dagger.Binds
4+
import dagger.Module
5+
import dagger.hilt.InstallIn
6+
import dagger.hilt.components.SingletonComponent
7+
import kotlinx.coroutines.flow.Flow
8+
import kotlinx.coroutines.flow.flowOf
9+
import ytemplate.android.data.MyModelRepository
10+
import ytemplate.android.data.MyModelRepositoryImpl
11+
import javax.inject.Inject
12+
13+
@Module
14+
@InstallIn(SingletonComponent::class)
15+
interface DataModule {
16+
@Binds
17+
fun bindMyModelRepository(myModelRepository: MyModelRepositoryImpl): MyModelRepository
18+
}
19+
20+
class FakeMyModelRepository @Inject constructor(): MyModelRepository {
21+
override val myModel: Flow<List<String>>
22+
get() = flowOf(fakeData)
23+
24+
override suspend fun add(name: String) {
25+
TODO("Not yet implemented")
26+
}
27+
}
28+
val fakeData = listOf("test1","test2","test3")

0 commit comments

Comments
 (0)