Skip to content

Commit 755cabf

Browse files
added android test sample
1 parent 01317b1 commit 755cabf

79 files changed

Lines changed: 1477 additions & 107 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AndroidTestingSample/.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/caches
5+
/.idea/libraries
6+
/.idea/modules.xml
7+
/.idea/workspace.xml
8+
/.idea/navEditor.xml
9+
/.idea/assetWizardSettings.xml
10+
.DS_Store
11+
/build
12+
/captures
13+
.externalNativeBuild
14+
.cxx
15+
local.properties
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
plugins {
2+
id("com.android.application")
3+
id("org.jetbrains.kotlin.android")
4+
id("kotlin-kapt")
5+
id("com.google.dagger.hilt.android")
6+
}
7+
8+
android {
9+
namespace = "com.example.androidtestingsample"
10+
compileSdk = 33
11+
12+
defaultConfig {
13+
applicationId = "com.example.androidtestingsample"
14+
minSdk = 28
15+
targetSdk = 33
16+
versionCode = 1
17+
versionName = "1.0"
18+
19+
testInstrumentationRunner = "com.example.androidtestingsample.CustomTestRunner"
20+
}
21+
22+
buildTypes {
23+
release {
24+
isMinifyEnabled = false
25+
proguardFiles(
26+
getDefaultProguardFile("proguard-android-optimize.txt"),
27+
"proguard-rules.pro"
28+
)
29+
}
30+
}
31+
compileOptions {
32+
sourceCompatibility = JavaVersion.VERSION_17
33+
targetCompatibility = JavaVersion.VERSION_17
34+
}
35+
kotlinOptions {
36+
jvmTarget = "17"
37+
}
38+
39+
buildFeatures {
40+
viewBinding = true
41+
dataBinding = true
42+
}
43+
44+
packaging {
45+
resources.excludes.add("META-INF/*")
46+
jniLibs.useLegacyPackaging = false
47+
}
48+
49+
}
50+
51+
dependencies {
52+
53+
implementation("androidx.core:core-ktx:1.9.0")
54+
implementation("androidx.appcompat:appcompat:1.6.1")
55+
implementation("com.google.android.material:material:1.9.0")
56+
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
57+
testImplementation("junit:junit:4.13.2")
58+
androidTestImplementation("androidx.test.ext:junit:1.1.5")
59+
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
60+
61+
//hilt
62+
implementation("com.google.dagger:hilt-android:2.44")
63+
kapt("com.google.dagger:hilt-compiler:2.44")
64+
65+
// Navigation
66+
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
67+
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
68+
69+
// Networking
70+
implementation("com.squareup.retrofit2:retrofit:2.9.0")
71+
implementation("com.squareup.okhttp3:okhttp:4.11.0")
72+
implementation("com.squareup.okhttp3:logging-interceptor:4.7.2")
73+
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
74+
75+
//Coroutine
76+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.2")
77+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2")
78+
implementation("com.google.code.gson:gson:2.9.0")
79+
implementation("androidx.activity:activity-ktx:1.7.2")
80+
81+
// hilt android test
82+
androidTestImplementation("com.google.dagger:hilt-android-testing:2.44")
83+
kaptAndroidTest("com.google.dagger:hilt-android-compiler:2.44")
84+
85+
// android espresso
86+
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
87+
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.5.1")
88+
androidTestImplementation("androidx.test.espresso:espresso-intents:3.5.1")
89+
implementation("androidx.test.espresso:espresso-idling-resource:3.5.1")
90+
androidTestImplementation("androidx.test.espresso:espresso-idling-resource:3.5.1")
91+
92+
// mockk
93+
androidTestImplementation("io.mockk:mockk-android:1.13.5")
94+
androidTestImplementation("io.mockk:mockk-agent:1.13.5")
95+
}
96+
kapt {
97+
correctErrorTypes=true
98+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.example.androidtestingsample
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 CustomTestRunner : AndroidJUnitRunner() {
9+
10+
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
11+
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
12+
}
13+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.example.androidtestingsample
2+
3+
import androidx.test.platform.app.InstrumentationRegistry
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
9+
import org.junit.Assert.*
10+
11+
/**
12+
* Instrumented test, which will execute on an Android device.
13+
*
14+
* See [testing documentation](http://d.android.com/tools/testing).
15+
*/
16+
@RunWith(AndroidJUnit4::class)
17+
class ExampleInstrumentedTest {
18+
@Test
19+
fun useAppContext() {
20+
// Context of the app under test.
21+
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22+
assertEquals("com.example.androidtestingsample", appContext.packageName)
23+
}
24+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (C) 2019 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.androidtestingsample
18+
19+
import android.content.ComponentName
20+
import android.content.Intent
21+
import android.os.Bundle
22+
import androidx.annotation.StyleRes
23+
import androidx.core.util.Preconditions
24+
import androidx.fragment.app.Fragment
25+
import androidx.fragment.app.FragmentFactory
26+
import androidx.test.core.app.ActivityScenario
27+
import androidx.test.core.app.ApplicationProvider
28+
import kotlinx.coroutines.ExperimentalCoroutinesApi
29+
30+
/**
31+
* launchFragmentInContainer from the androidx.fragment:fragment-testing library
32+
* is NOT possible to use right now as it uses a hardcoded Activity under the hood
33+
* (i.e. [EmptyFragmentActivity]) which is not annotated with @AndroidEntryPoint.
34+
*
35+
* As a workaround, use this function that is equivalent. It requires you to add
36+
* [HiltTestActivity] in the debug folder and include it in the debug AndroidManifest.xml file
37+
* as can be found in this project.
38+
*/
39+
const val THEME_EXTRAS_BUNDLE_KEY = "androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY"
40+
@ExperimentalCoroutinesApi
41+
inline fun <reified T : Fragment> launchFragmentInHiltContainer(
42+
fragmentArgs: Bundle? = null,
43+
themeResId: Int = R.style.Theme_AndroidTestingSample,
44+
fragmentFactory: FragmentFactory? = null,
45+
crossinline action: T.() -> Unit = {}
46+
) {
47+
val mainActivityIntent = Intent.makeMainActivity(
48+
ComponentName(
49+
ApplicationProvider.getApplicationContext(),
50+
HiltTestActivity::class.java
51+
)
52+
).putExtra(THEME_EXTRAS_BUNDLE_KEY, themeResId)
53+
ActivityScenario.launch<HiltTestActivity>(mainActivityIntent).onActivity { activity ->
54+
fragmentFactory?.let {
55+
activity.supportFragmentManager.fragmentFactory = it
56+
}
57+
val fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
58+
Preconditions.checkNotNull(T::class.java.classLoader),
59+
T::class.java.name
60+
)
61+
fragment.arguments = fragmentArgs
62+
activity.supportFragmentManager.beginTransaction()
63+
.add(android.R.id.content, fragment, "")
64+
.commitNow()
65+
(fragment as T).action()
66+
}
67+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.example.androidtestingsample.data
2+
3+
val MOVIE_LIST = listOf(Movie("name","",""),Movie("name","",""))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.example.androidtestingsample.data
2+
3+
import com.example.androidtestingsample.data.MainRepository
4+
import com.example.androidtestingsample.data.Movie
5+
import javax.inject.Inject
6+
7+
class TestRepository @Inject constructor(): MainRepository {
8+
override suspend fun getAllMovies(): List<Movie> {
9+
return MOVIE_LIST
10+
}
11+
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.example.androidtestingsample.di
2+
3+
import com.example.androidtestingsample.data.MainRepository
4+
import com.example.androidtestingsample.data.MainRepositoryImpl
5+
import com.example.androidtestingsample.data.TestRepository
6+
import dagger.Binds
7+
import dagger.Module
8+
import dagger.hilt.InstallIn
9+
import dagger.hilt.android.components.ViewModelComponent
10+
import dagger.hilt.testing.TestInstallIn
11+
12+
@Module
13+
@TestInstallIn(components = [ViewModelComponent::class], replaces = [RepositoriesModule::class])
14+
interface TestRepositoriesModule {
15+
16+
@Binds
17+
fun mainRepository(mainRepositoryImpl: TestRepository): MainRepository
18+
}

0 commit comments

Comments
 (0)