diff --git a/app-shared-test/.gitignore b/app-shared-test/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app-shared-test/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app-shared-test/build.gradle b/app-shared-test/build.gradle new file mode 100644 index 0000000..deeb0dc --- /dev/null +++ b/app-shared-test/build.gradle @@ -0,0 +1,49 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk 31 + + defaultConfig { + minSdk 21 + targetSdk 31 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + assets.srcDirs += files("$projectDir/../app/schemas".toString()) + resources.srcDirs += files("$projectDir/../app/schemas".toString()) + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +// since it itself contains the Test it doesn't have tests of it's own +disableTestTasks(this) + +dependencies { + implementation project(":app") + implementation project(':test-util-android') + implementation testFixtures(project(':core')) + implementation "io.insert-koin:koin-android:$koin_version" + implementation project(':test-util-shared-robolectric') + + applyAppSharedTestDependenciesTo(this) +} \ No newline at end of file diff --git a/app-shared-test/consumer-rules.pro b/app-shared-test/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/app-shared-test/proguard-rules.pro b/app-shared-test/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app-shared-test/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app-shared-test/src/main/AndroidManifest.xml b/app-shared-test/src/main/AndroidManifest.xml new file mode 100644 index 0000000..617ac35 --- /dev/null +++ b/app-shared-test/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedSharedTest.kt similarity index 97% rename from app/src/sharedTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedSharedTest.kt index a2527aa..4061051 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt +++ b/app-shared-test/src/main/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedSharedTest.kt @@ -23,7 +23,7 @@ import java.io.IOException * https://developer.android.com/training/data-storage/room/migrating-db-versions */ @RunWith(AndroidJUnit4::class) -class MigrationToLatestInstrumentedTest { +open class MigrationToLatestInstrumentedSharedTest { @get:Rule val helper = SharedMigrationTestRule(instrumentation = InstrumentationRegistry.getInstrumentation()) @@ -48,7 +48,7 @@ class MigrationToLatestInstrumentedTest { @Test @Throws(IOException::class) - fun migrate1To2() { + open fun migrate1To2() { val expectedEntities = setOf( FavouriteEntity("123"), FavouriteEntity("124"), diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/MockServerScenarioSetupResetingTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/ReloadKoinModulesIfNecessaryTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/AsyncDiffUtilInstantTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/AsyncDiffUtilInstantTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/AsyncDiffUtilInstantTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/AsyncDiffUtilInstantTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/DatabaseDispatcherTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/DatabaseDispatcherTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/DatabaseDispatcherTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/DatabaseDispatcherTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/MainDispatcherTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/MainDispatcherTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/MainDispatcherTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/MainDispatcherTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/idling/NetworkSynchronizationTestRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/statesetup/SetupAuthenticationState.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/testutils/storage/TestDatabaseInitialization.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/testutils/storage/TestDatabaseInitialization.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/testutils/storage/TestDatabaseInitialization.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/testutils/storage/TestDatabaseInitialization.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/home/HomeRobot.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/home/HomeRobot.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/home/HomeRobot.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedSharedTest.kt similarity index 99% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedSharedTest.kt index 7b4af06..1678675 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt +++ b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedSharedTest.kt @@ -26,7 +26,7 @@ import org.koin.test.KoinTest @Suppress("TestFunctionName") @RunWith(AndroidJUnit4::class) -class MainActivityInstrumentedTest : KoinTest { +open class MainActivityInstrumentedSharedTest : KoinTest { private lateinit var activityScenario: ActivityScenario diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedSharedTest.kt similarity index 98% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedSharedTest.kt index 7d7159d..d838949 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt +++ b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedSharedTest.kt @@ -21,7 +21,7 @@ import org.koin.test.KoinTest @Suppress("TestFunctionName") @RunWith(AndroidJUnit4::class) -class AuthActivityInstrumentedTest : KoinTest { +open class AuthActivityInstrumentedSharedTest : KoinTest { private lateinit var activityScenario: ActivityScenario diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/LoginRobot.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/LoginRobot.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/LoginRobot.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/LoginRobot.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt similarity index 94% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt index 30de5cf..07b66a0 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt +++ b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivitySharedTest.kt @@ -13,7 +13,8 @@ import org.koin.test.KoinTest @RunWith(AndroidJUnit4::class) @OptIn(ExperimentalCoroutinesApi::class) @Ignore("CodeKata") -class CodeKataAuthActivitySharedTest : KoinTest { +@Suppress("EmptyFunctionBlock") +open class CodeKataAuthActivitySharedTest : KoinTest { @Before fun setup() { diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataSharedRobotTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/CodeKataSharedRobotTest.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataSharedRobotTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/CodeKataSharedRobotTest.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/CodeKataMainDispatcherRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/CodeKataMainDispatcherRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/CodeKataMainDispatcherRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/CodeKataMainDispatcherRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/PlainMainDispatcherRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/PlainMainDispatcherRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/PlainMainDispatcherRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/dispatcher/PlainMainDispatcherRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/CodeKataIntentInitRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/CodeKataIntentInitRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/CodeKataIntentInitRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/CodeKataIntentInitRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/PlainIntentInitRule.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/PlainIntentInitRule.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/PlainIntentInitRule.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/login/codekata/rule/intent/PlainIntentInitRule.kt diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedSharedTest.kt similarity index 95% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedSharedTest.kt index 9c72866..f08761a 100644 --- a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt +++ b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedSharedTest.kt @@ -3,7 +3,6 @@ package org.fnives.test.showcase.ui.splash import androidx.lifecycle.Lifecycle import androidx.test.core.app.ActivityScenario import androidx.test.espresso.intent.Intents -import androidx.test.ext.junit.runners.AndroidJUnit4 import org.fnives.test.showcase.android.testutil.activity.SafeCloseActivityRule import org.fnives.test.showcase.android.testutil.intent.DismissSystemDialogsRule import org.fnives.test.showcase.android.testutil.screenshot.ScreenshotRule @@ -16,12 +15,10 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain -import org.junit.runner.RunWith import org.koin.test.KoinTest @Suppress("TestFunctionName") -@RunWith(AndroidJUnit4::class) -class SplashActivityInstrumentedTest : KoinTest { +open class SplashActivityInstrumentedSharedTest : KoinTest { private lateinit var activityScenario: ActivityScenario diff --git a/app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt b/app-shared-test/src/main/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt similarity index 100% rename from app/src/sharedTest/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt rename to app-shared-test/src/main/java/org/fnives/test/showcase/ui/splash/SplashRobot.kt diff --git a/app/build.gradle b/app/build.gradle index 7d3b0e4..7234e88 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,13 +42,11 @@ android { sourceSets { androidTest { - java.srcDirs += "src/sharedTest/java" - assets.srcDirs += files("$projectDir/schemas".toString()) +// assets.srcDirs += files("$projectDir/schemas".toString()) } test { - java.srcDirs += "src/sharedTest/java" java.srcDirs += "src/robolectricTest/java" - resources.srcDirs += files("$projectDir/schemas".toString()) +// resources.srcDirs += files("$projectDir/schemas".toString()) } } @@ -115,6 +113,9 @@ dependencies { testImplementation testFixtures(project(':core')) androidTestImplementation testFixtures(project(':core')) + testImplementation project(':app-shared-test') + androidTestImplementation project(':app-shared-test') + // case specific implementation project(":examplecase:example-navcontroller") } diff --git a/app/src/androidTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt new file mode 100644 index 0000000..e59caf7 --- /dev/null +++ b/app/src/androidTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.storage.migration + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MigrationToLatestInstrumentedTest : MigrationToLatestInstrumentedSharedTest() diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt new file mode 100644 index 0000000..c348e32 --- /dev/null +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.home + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MainActivityInstrumentedTest : MainActivityInstrumentedSharedTest() diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt new file mode 100644 index 0000000..78b6753 --- /dev/null +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.login + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class AuthActivityInstrumentedTest : AuthActivityInstrumentedSharedTest() diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt new file mode 100644 index 0000000..5b9236d --- /dev/null +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt @@ -0,0 +1,9 @@ +package org.fnives.test.showcase.ui.login.codekata + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Ignore +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@Ignore("CodeKata") +class CodeKataAuthActivityTest : CodeKataAuthActivitySharedTest() diff --git a/app/src/androidTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt b/app/src/androidTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt new file mode 100644 index 0000000..2d44cf1 --- /dev/null +++ b/app/src/androidTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.splash + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SplashActivityInstrumentedTest : SplashActivityInstrumentedSharedTest() diff --git a/app/src/robolectricTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt b/app/src/robolectricTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt new file mode 100644 index 0000000..e59caf7 --- /dev/null +++ b/app/src/robolectricTest/java/org/fnives/test/showcase/storage/migration/MigrationToLatestInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.storage.migration + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MigrationToLatestInstrumentedTest : MigrationToLatestInstrumentedSharedTest() diff --git a/app/src/robolectricTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt new file mode 100644 index 0000000..c348e32 --- /dev/null +++ b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/home/MainActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.home + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class MainActivityInstrumentedTest : MainActivityInstrumentedSharedTest() diff --git a/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt new file mode 100644 index 0000000..78b6753 --- /dev/null +++ b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/AuthActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.login + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class AuthActivityInstrumentedTest : AuthActivityInstrumentedSharedTest() diff --git a/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt new file mode 100644 index 0000000..5b9236d --- /dev/null +++ b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/login/codekata/CodeKataAuthActivityTest.kt @@ -0,0 +1,9 @@ +package org.fnives.test.showcase.ui.login.codekata + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Ignore +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@Ignore("CodeKata") +class CodeKataAuthActivityTest : CodeKataAuthActivitySharedTest() diff --git a/app/src/robolectricTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt new file mode 100644 index 0000000..2d44cf1 --- /dev/null +++ b/app/src/robolectricTest/java/org/fnives/test/showcase/ui/splash/SplashActivityInstrumentedTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.ui.splash + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SplashActivityInstrumentedTest : SplashActivityInstrumentedSharedTest() diff --git a/build.gradle b/build.gradle index d055725..40d384d 100644 --- a/build.gradle +++ b/build.gradle @@ -45,4 +45,5 @@ apply from: 'gradlescripts/ktlint.gradle' apply from: 'gradlescripts/lint.gradle' apply from: 'gradlescripts/testoptions.gradle' apply from: 'gradlescripts/test.tasks.gradle' -apply from: 'gradlescripts/testdependencies.gradle' \ No newline at end of file +apply from: 'gradlescripts/testdependencies.gradle' +apply from: 'gradlescripts/disable.test.task.gradle' \ No newline at end of file diff --git a/codekata/sharedtests.instructionset.md b/codekata/sharedtests.instructionset.md index 2034ecc..5bbb35c 100644 --- a/codekata/sharedtests.instructionset.md +++ b/codekata/sharedtests.instructionset.md @@ -13,7 +13,12 @@ In this testing instruction set you will learn how to write simple tests running ## Login UI Test Instead of writing new tests from scratch, we will modify our existing Robolectric tests so they can be run on a Real Android device as well.N -For this we already have a `sharedTest` package. +For this we already have a ~~`sharedTest` package~~ a separate app-shared-test module. + +> Sharing sourceSets between unitTest and androidTest is no longer supported in Android Studio. +> You may find a bunch of artiles referencing that way of sharing or even on Robolectric sites, but these are now outdated. +> We are using the recommendation to that issue which is a shared-test module which depends on :app and it's tests depend on the module. testImplementation project(:shared-test) androidTestImplementation project(:shared-test). +> This may seem circular at first, but it's not: shared-test depends on app's main, while app's Tests depend on shared-test. Our classes will be `CodeKataAuthActivitySharedTest` and `CodeKataSharedRobotTest`. @@ -34,8 +39,8 @@ Let's open `org.fnives.test.showcase.ui.login.codekata.CodeKataAuthActivityShare We can see it's identical as our original `org.fnives.test.showcase.ui.codekata.CodeKataAuthActivityInstrumentedTest`. So let's copy our existing code from the Robolectric test here. For that we can use the body of `org.fnives.test.showcase.ui.RobolectricAuthActivityInstrumentedTest`. -You immediately notice that there are no import issues. That's because sharedTest package is added to the test sources. You may check out the `app/build.gradle` to see how that's done. -However we need to modify our robot: +Of course keep the `open` and the `CodeKataAuthActivitySharedTest` class name and package. +We need to modify our robot: ```kotlin // Instead of this: private lateinit var robot: RobolectricLoginRobot @@ -51,11 +56,25 @@ robot = CodeKataSharedRobotTest() For our starting point, this is all the setup we need. What we now will do is modify this piece of class, so it not only runs via Robolectric, but it can run on Real Devices as well. +Now, go to the classes that extend this and remove the `@Ignore("CodeKata")` annotation: `CodeKataAuthActivityTest` in both `unitTest` and `androidTest`. + +> This child classes run when testing so we are sharing a base class, but the child classess will run every Test of the Base class. + ### 1. Threads So to discover the differences, let's handle them one by one, by Running our Test. -In shared tests, at least for me, it defaults to Android Test when running the class. So make sure your device is connected, and run the `invalidCredentialsGivenShowsProperErrorMessage` Test. It should start on your device and shall crash. -You will see something similar: +Open `CodeKataAuthActivityTest` inside `androidTest` and overwrite `invalidCredentialsGivenShowsProperErrorMessage`: +```kotlin +@RunWith(AndroidJUnit4::class) +class CodeKataAuthActivityTest : CodeKataAuthActivitySharedTest() { +// if invalidCredentialsGivenShowsProperErrorMessage is not open in base, open it + override fun invalidCredentialsGivenShowsProperErrorMessage() { + super.invalidCredentialsGivenShowsProperErrorMessage() + } +} +``` +Make sure your device (tested on API=30) is connected, and run the `invalidCredentialsGivenShowsProperErrorMessage` Test. It should start on your device and shall crash. +You will see something similar in logcat: ```kotlin java.lang.IllegalStateException: Cannot invoke setValue on a background thread at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487) @@ -66,7 +85,7 @@ So that brings us to the first difference: *while Robolectric uses the same thre So the issue is with this line: `testDispatcher.advanceUntilIdleWithIdlingResources()`. Since we are in the InstrumentedTest's thread, all our coroutines will run there as well, which doesn't play well with LiveData. One idea would be to use LiveData `ArchTaskExecutor.getInstance()` and ensure our LiveData doesn't care about the Thread they are set from, **but** then we would touch our Views from Non-Main Thread, which is still an issue. -**So Instead** What we need to do is run our coroutines on the actual mainThread. We have a handy `runOnUIAwaitOnCurrent` function for that, so let's use it in our `invalidCredentialsGivenShowsProperErrorMessage` test, wrap around our dispatcher call. +**So Instead** What we need to do is run our coroutines on the actual mainThread. We have a handy `runOnUIAwaitOnCurrent` function for that, so let's use it in our `invalidCredentialsGivenShowsProperErrorMessage` (inside the base class) test, wrap around our dispatcher call. The full function now will look like this: ```kotlin @@ -458,7 +477,7 @@ To resolve this fast, a possible way is like this: Another issue can be that Crashlytics or similar services is enabled in your tests. This can be resolved by the same principle as the HiltTestApplication issue, aka custom `AndroidJunitRunner`. Your custom TestClass will initialize only what it needs to. #### 4. Dialogs -Dialogs cannot be tested properly via Robolectric without usage of Shadows, but they can be on Real Device. So what I usually do is setup a function which does one thing in one sourceset while does something else in another. You can see such example like `SpecificTestConfigurationsFactory`. To ease the usage I usually put a function in the sharedTest which uses the object `SpecificTestConfigurationsFactory`. +Dialogs cannot be tested properly via Robolectric without usage of Shadows, but they can be on Real Device. So what I usually do is setup a function which does one thing in one sourceset while does something else in another. So either you will have to test them only on real device, or you can create helper module which in AndroidTest uses actual Espresso calls, while if Robolectric is active it uses the Shadow. See how `SharedMigrationTestRule` is setup and extended. #### 5. Resource Access Accessing test Resource files can also be an issue, you might not able to access your same test/res folder in AndroidTests. A way to do this is to declare the same folder as androidTest/assets in build gradle and similar to dialogs, create a function which uses Assets in Android Tests and uses Resources in Robolectric tests. diff --git a/examplecase/example-navcontroller-shared-test/.gitignore b/examplecase/example-navcontroller-shared-test/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/examplecase/example-navcontroller-shared-test/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/examplecase/example-navcontroller-shared-test/build.gradle b/examplecase/example-navcontroller-shared-test/build.gradle new file mode 100644 index 0000000..a33e5ad --- /dev/null +++ b/examplecase/example-navcontroller-shared-test/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' + id 'androidx.navigation.safeargs.kotlin' +} + +android { + compileSdk 31 + + defaultConfig { + minSdk 21 + targetSdk 31 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + + lintOptions { + ignore 'FragmentGradleConfiguration' + } +} + +// since it itself contains the Test it doesn't have tests of it's own +disableTestTasks(this) + +dependencies { + applyAppSharedTestDependenciesTo(this) + implementation project(":examplecase:example-navcontroller") + //noinspection FragmentGradleConfiguration + implementation "androidx.fragment:fragment-testing:1.5.3" + implementation "androidx.navigation:navigation-testing:$navigation_version" + implementation project(':test-util-android') +} \ No newline at end of file diff --git a/examplecase/example-navcontroller-shared-test/consumer-rules.pro b/examplecase/example-navcontroller-shared-test/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/examplecase/example-navcontroller-shared-test/proguard-rules.pro b/examplecase/example-navcontroller-shared-test/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/examplecase/example-navcontroller-shared-test/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examplecase/example-navcontroller-shared-test/src/main/AndroidManifest.xml b/examplecase/example-navcontroller-shared-test/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6f663a2 --- /dev/null +++ b/examplecase/example-navcontroller-shared-test/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/examplecase/example-navcontroller/src/sharedTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt b/examplecase/example-navcontroller-shared-test/src/main/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationSharedTest.kt similarity index 90% rename from examplecase/example-navcontroller/src/sharedTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt rename to examplecase/example-navcontroller-shared-test/src/main/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationSharedTest.kt index 6943f0f..45143ba 100644 --- a/examplecase/example-navcontroller/src/sharedTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt +++ b/examplecase/example-navcontroller-shared-test/src/main/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationSharedTest.kt @@ -28,7 +28,7 @@ import org.junit.runner.RunWith * For more info check out https://developer.android.com/guide/navigation/navigation-testing */ @RunWith(AndroidJUnit4::class) -class HomeNavigationTest { +open class HomeNavigationSharedTest { private lateinit var fragmentScenario: FragmentScenario private lateinit var testNavController: TestNavHostController @@ -80,7 +80,8 @@ class HomeNavigationTest { .perform(ViewActions.click()) Assert.assertEquals(R.id.detailFragment, testNavController.currentDestination?.id) - Assert.assertEquals(listOf(R.id.nav_example_xml, R.id.homeFragment, R.id.detailFragment), testNavController.backStack.map { it.destination.id }) + val expectedBackstack = listOf(R.id.nav_example_xml, R.id.homeFragment, R.id.detailFragment) + Assert.assertEquals(expectedBackstack, testNavController.backStack.map { it.destination.id }) testNavController.backStack.map { it.arguments } } @@ -95,7 +96,8 @@ class HomeNavigationTest { Espresso.onView(itemViewMatcher(position2)).perform(ViewActions.click()) Assert.assertEquals(R.id.detailFragment, testNavController.currentDestination?.id) - Assert.assertEquals(listOf(R.id.nav_example_xml, R.id.homeFragment, R.id.detailFragment), testNavController.backStack.map { it.destination.id }) + val expectedBackstack = listOf(R.id.nav_example_xml, R.id.homeFragment, R.id.detailFragment) + Assert.assertEquals(expectedBackstack, testNavController.backStack.map { it.destination.id }) val actualArgs = DetailFragmentArgs.fromBundle(testNavController.backStack.last().arguments ?: Bundle()) Assert.assertEquals(position1, actualArgs.position) } diff --git a/examplecase/example-navcontroller/build.gradle b/examplecase/example-navcontroller/build.gradle index 914af41..323fbee 100644 --- a/examplecase/example-navcontroller/build.gradle +++ b/examplecase/example-navcontroller/build.gradle @@ -28,17 +28,6 @@ android { kotlinOptions { jvmTarget = '1.8' } - sourceSets { - androidTest { - java.srcDirs += "src/sharedTest/java" - assets.srcDirs += files("$projectDir/schemas".toString()) - } - test { - java.srcDirs += "src/sharedTest/java" - java.srcDirs += "src/robolectricTest/java" - resources.srcDirs += files("$projectDir/schemas".toString()) - } - } // needed for androidTest packagingOptions { @@ -56,12 +45,8 @@ dependencies { implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" - debugImplementation "androidx.fragment:fragment-testing:1.5.3" - applyAppTestDependenciesTo(this) - - testImplementation "androidx.navigation:navigation-testing:$navigation_version" - testImplementation project(':test-util-android') - androidTestImplementation project(':test-util-android') - androidTestImplementation "androidx.navigation:navigation-testing:$navigation_version" + debugImplementation "androidx.fragment:fragment-testing:1.5.3" + testImplementation project(":examplecase:example-navcontroller-shared-test") + androidTestImplementation project(":examplecase:example-navcontroller-shared-test") } \ No newline at end of file diff --git a/examplecase/example-navcontroller/src/androidTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt b/examplecase/example-navcontroller/src/androidTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt new file mode 100644 index 0000000..b2de66d --- /dev/null +++ b/examplecase/example-navcontroller/src/androidTest/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.examplecase.navcontroller + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class HomeNavigationTest : HomeNavigationSharedTest() diff --git a/examplecase/example-navcontroller/src/test/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt b/examplecase/example-navcontroller/src/test/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt new file mode 100644 index 0000000..b2de66d --- /dev/null +++ b/examplecase/example-navcontroller/src/test/java/org/fnives/test/showcase/examplecase/navcontroller/HomeNavigationTest.kt @@ -0,0 +1,7 @@ +package org.fnives.test.showcase.examplecase.navcontroller + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class HomeNavigationTest : HomeNavigationSharedTest() diff --git a/gradlescripts/disable.test.task.gradle b/gradlescripts/disable.test.task.gradle new file mode 100644 index 0000000..5979e98 --- /dev/null +++ b/gradlescripts/disable.test.task.gradle @@ -0,0 +1,10 @@ +project.ext { + // helper function to disable Test Tasks in modules where there are no tests and so the Tests are not required. + disableTestTasks = { module -> + module.tasks.whenTaskAdded { task -> + if(task.name.contains("Test")) { + task.enabled = false + } + } + } +} \ No newline at end of file diff --git a/gradlescripts/testdependencies.gradle b/gradlescripts/testdependencies.gradle index f4ce4b8..ef2187d 100644 --- a/gradlescripts/testdependencies.gradle +++ b/gradlescripts/testdependencies.gradle @@ -21,6 +21,10 @@ project.ext { applyAppTestDependenciesTo(this) applyComposeTestDependenciesTo(this) // if you are using compose } + -------------APP-SHARED-TEST(Android Module------------- + dependencies { + applyAppSharedTestDependenciesTo(this) + } ------------------VERSIONS------------------ versions try to get the global value, if not found they fall back to some defaults. @@ -77,18 +81,24 @@ project.ext { ] // ------------------PRIVATE------------------ - def applyStandardTestDependenciesTo = { module -> - module.dependencies { + def standardTestDependencies = [ // coroutine testing - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$test_coroutines_version" + "org.jetbrains.kotlinx:kotlinx-coroutines-test:$test_coroutines_version", // mockito, mocking library - testImplementation "org.mockito.kotlin:mockito-kotlin:$testing_kotlin_mockito_version" + "org.mockito.kotlin:mockito-kotlin:$testing_kotlin_mockito_version", - testImplementation "io.insert-koin:koin-test-junit5:$testing_koin_version" + "io.insert-koin:koin-test-junit5:$testing_koin_version", // junit5 - testImplementation "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version" - testImplementation "org.junit.jupiter:junit-jupiter-params:$testing_junit5_version" + "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version", + "org.junit.jupiter:junit-jupiter-params:$testing_junit5_version", + ] + + def applyStandardTestDependenciesTo = { module -> + module.dependencies { + standardTestDependencies.forEach { dependency -> + testImplementation dependency + } testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version" } } @@ -137,6 +147,21 @@ project.ext { } } + // ------------APP-SHARED-TEST------------ + applyAppSharedTestDependenciesTo = { module -> + + module.dependencies { + standardTestDependencies.forEach { dependency -> + implementation dependency + } + androidSpecificTestDependencies.forEach { dependency -> + implementation dependency + } + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$test_coroutines_version" + implementation "io.insert-koin:koin-test-junit5:$testing_koin_version" + } + } + // ------------------COMPOSE------------------ applyComposeTestDependenciesTo = { module -> module.dependencies { diff --git a/settings.gradle b/settings.gradle index d372230..1306dfa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,6 @@ include ':test-util-shared-android' include ':test-util-shared-robolectric' include ':test-util-android' include ':test-util-junit5-android' +include ':app-shared-test' include ':examplecase:example-navcontroller' +include ':examplecase:example-navcontroller-shared-test'