P0.2: Android test infrastructure (TDD foundation)

- Add androidUnitTest source set: JUnit 4, Robolectric 4.14.1, mockk, androidx.test
- Add androidInstrumentedTest source set: androidx.test.ext, espresso, mockk-android
- Pin Robolectric to SDK 34 (Robolectric 4.14.1 doesn't yet support compileSdk 36)
- Enable includeAndroidResources for Robolectric
- Canary tests green on both source sets

Verifies:
  ./gradlew :composeApp:testDebugUnitTest
  ./gradlew :composeApp:compileDebugAndroidTestSources

Part of Android -> iOS parity plan (rc-android-ios-parity.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-18 12:25:50 -05:00
parent 42b7392f39
commit 74adaab6df
5 changed files with 78 additions and 0 deletions

View File

@@ -116,6 +116,26 @@ kotlin {
implementation(libs.ktor.client.mock)
implementation(libs.kotlinx.coroutines.test)
}
val androidUnitTest by getting {
dependencies {
implementation(libs.kotlin.testJunit)
implementation(libs.junit)
implementation(libs.robolectric)
implementation(libs.mockk)
implementation(libs.kotlinx.coroutines.test)
implementation(libs.androidx.test.core)
implementation(libs.androidx.test.core.ktx)
implementation(libs.androidx.testExt.junit)
}
}
val androidInstrumentedTest by getting {
dependencies {
implementation(libs.androidx.testExt.junit)
implementation(libs.androidx.espresso.core)
implementation(libs.androidx.test.runner)
implementation(libs.mockk.android)
}
}
}
}
@@ -129,10 +149,12 @@ android {
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
excludes += "/META-INF/LICENSE*"
}
}
buildTypes {
@@ -147,6 +169,10 @@ android {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
testOptions {
unitTests.isIncludeAndroidResources = true
unitTests.isReturnDefaultValues = true
}
}
dependencies {

View File

@@ -0,0 +1,17 @@
package com.tt.honeyDue
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CanaryInstrumentedTest {
@Test
fun app_context_available() {
val appContext = ApplicationProvider.getApplicationContext<android.content.Context>()
assertTrue(appContext.packageName.startsWith("com.tt.honeyDue"))
}
}

View File

@@ -0,0 +1,22 @@
package com.tt.honeyDue
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class CanaryUnitTest {
@Test
fun arithmetic_sanity() {
assertEquals(2, 1 + 1)
}
@Test
fun robolectric_android_runtime_available() {
val appContext = androidx.test.core.app.ApplicationProvider.getApplicationContext<android.content.Context>()
assertTrue(appContext.packageName.startsWith("com.tt.honeyDue"))
}
}

View File

@@ -0,0 +1 @@
sdk=34

View File

@@ -22,6 +22,10 @@ ktor = "3.3.1"
firebase-bom = "34.0.0"
google-services = "4.4.3"
billing = "7.1.1"
robolectric = "4.14.1"
mockk = "1.13.13"
androidx-test-runner = "1.6.2"
androidx-test-core = "1.6.1"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
@@ -58,6 +62,14 @@ coil-network-ktor3 = { module = "io.coil-kt.coil3:coil-network-ktor3", version.r
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" }
firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }
google-billing = { module = "com.android.billingclient:billing-ktx", version.ref = "billing" }
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" }
androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" }
androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test-core" }
androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test-core" }
compose-ui-test-junit4-android = { module = "androidx.compose.ui:ui-test-junit4-android", version = "1.7.5" }
compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version = "1.7.5" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }