Merge pull request #124 from fknives/issue#106-update-shared-tests

Issue#106 update shared tests
This commit is contained in:
Gergely Hegedis 2022-09-26 21:51:52 +03:00 committed by GitHub
commit b6b661b055
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 330 additions and 49 deletions

1
app-shared-test/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -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)
}

View file

21
app-shared-test/proguard-rules.pro vendored Normal file
View file

@ -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

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fnives.test.showcase.test.shared">
</manifest>

View file

@ -23,7 +23,7 @@ import java.io.IOException
* https://developer.android.com/training/data-storage/room/migrating-db-versions * https://developer.android.com/training/data-storage/room/migrating-db-versions
*/ */
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class MigrationToLatestInstrumentedTest { open class MigrationToLatestInstrumentedSharedTest {
@get:Rule @get:Rule
val helper = SharedMigrationTestRule<LocalDatabase>(instrumentation = InstrumentationRegistry.getInstrumentation()) val helper = SharedMigrationTestRule<LocalDatabase>(instrumentation = InstrumentationRegistry.getInstrumentation())
@ -48,7 +48,7 @@ class MigrationToLatestInstrumentedTest {
@Test @Test
@Throws(IOException::class) @Throws(IOException::class)
fun migrate1To2() { open fun migrate1To2() {
val expectedEntities = setOf( val expectedEntities = setOf(
FavouriteEntity("123"), FavouriteEntity("123"),
FavouriteEntity("124"), FavouriteEntity("124"),

View file

@ -26,7 +26,7 @@ import org.koin.test.KoinTest
@Suppress("TestFunctionName") @Suppress("TestFunctionName")
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class MainActivityInstrumentedTest : KoinTest { open class MainActivityInstrumentedSharedTest : KoinTest {
private lateinit var activityScenario: ActivityScenario<MainActivity> private lateinit var activityScenario: ActivityScenario<MainActivity>

View file

@ -21,7 +21,7 @@ import org.koin.test.KoinTest
@Suppress("TestFunctionName") @Suppress("TestFunctionName")
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class AuthActivityInstrumentedTest : KoinTest { open class AuthActivityInstrumentedSharedTest : KoinTest {
private lateinit var activityScenario: ActivityScenario<AuthActivity> private lateinit var activityScenario: ActivityScenario<AuthActivity>

View file

@ -13,7 +13,8 @@ import org.koin.test.KoinTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@Ignore("CodeKata") @Ignore("CodeKata")
class CodeKataAuthActivitySharedTest : KoinTest { @Suppress("EmptyFunctionBlock")
open class CodeKataAuthActivitySharedTest : KoinTest {
@Before @Before
fun setup() { fun setup() {

View file

@ -3,7 +3,6 @@ package org.fnives.test.showcase.ui.splash
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.intent.Intents 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.activity.SafeCloseActivityRule
import org.fnives.test.showcase.android.testutil.intent.DismissSystemDialogsRule import org.fnives.test.showcase.android.testutil.intent.DismissSystemDialogsRule
import org.fnives.test.showcase.android.testutil.screenshot.ScreenshotRule import org.fnives.test.showcase.android.testutil.screenshot.ScreenshotRule
@ -16,12 +15,10 @@ import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import org.koin.test.KoinTest import org.koin.test.KoinTest
@Suppress("TestFunctionName") @Suppress("TestFunctionName")
@RunWith(AndroidJUnit4::class) open class SplashActivityInstrumentedSharedTest : KoinTest {
class SplashActivityInstrumentedTest : KoinTest {
private lateinit var activityScenario: ActivityScenario<SplashActivity> private lateinit var activityScenario: ActivityScenario<SplashActivity>

View file

@ -42,13 +42,11 @@ android {
sourceSets { sourceSets {
androidTest { androidTest {
java.srcDirs += "src/sharedTest/java" // assets.srcDirs += files("$projectDir/schemas".toString())
assets.srcDirs += files("$projectDir/schemas".toString())
} }
test { test {
java.srcDirs += "src/sharedTest/java"
java.srcDirs += "src/robolectricTest/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')) testImplementation testFixtures(project(':core'))
androidTestImplementation testFixtures(project(':core')) androidTestImplementation testFixtures(project(':core'))
testImplementation project(':app-shared-test')
androidTestImplementation project(':app-shared-test')
// case specific // case specific
implementation project(":examplecase:example-navcontroller") implementation project(":examplecase:example-navcontroller")
} }

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -46,3 +46,4 @@ apply from: 'gradlescripts/lint.gradle'
apply from: 'gradlescripts/testoptions.gradle' apply from: 'gradlescripts/testoptions.gradle'
apply from: 'gradlescripts/test.tasks.gradle' apply from: 'gradlescripts/test.tasks.gradle'
apply from: 'gradlescripts/testdependencies.gradle' apply from: 'gradlescripts/testdependencies.gradle'
apply from: 'gradlescripts/disable.test.task.gradle'

View file

@ -13,7 +13,12 @@ In this testing instruction set you will learn how to write simple tests running
## Login UI Test ## 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 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`. 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`. 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`. 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. Of course keep the `open` and the `CodeKataAuthActivitySharedTest` class name and package.
However we need to modify our robot: We need to modify our robot:
```kotlin ```kotlin
// Instead of this: // Instead of this:
private lateinit var robot: RobolectricLoginRobot 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. 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 ### 1. Threads
So to discover the differences, let's handle them one by one, by Running our Test. 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. Open `CodeKataAuthActivityTest` inside `androidTest` and overwrite `invalidCredentialsGivenShowsProperErrorMessage`:
You will see something similar: ```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 ```kotlin
java.lang.IllegalStateException: Cannot invoke setValue on a background thread java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487) 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. 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. 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: The full function now will look like this:
```kotlin ```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. 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 #### 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 #### 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. 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.

View file

@ -0,0 +1 @@
/build

View file

@ -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')
}

View file

@ -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

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.fnives.test.showcase.examplecase.navcontroller.shared.test">
</manifest>

View file

@ -28,7 +28,7 @@ import org.junit.runner.RunWith
* For more info check out https://developer.android.com/guide/navigation/navigation-testing * For more info check out https://developer.android.com/guide/navigation/navigation-testing
*/ */
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class HomeNavigationTest { open class HomeNavigationSharedTest {
private lateinit var fragmentScenario: FragmentScenario<HomeFragment> private lateinit var fragmentScenario: FragmentScenario<HomeFragment>
private lateinit var testNavController: TestNavHostController private lateinit var testNavController: TestNavHostController
@ -80,7 +80,8 @@ class HomeNavigationTest {
.perform(ViewActions.click()) .perform(ViewActions.click())
Assert.assertEquals(R.id.detailFragment, testNavController.currentDestination?.id) 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 } testNavController.backStack.map { it.arguments }
} }
@ -95,7 +96,8 @@ class HomeNavigationTest {
Espresso.onView(itemViewMatcher(position2)).perform(ViewActions.click()) Espresso.onView(itemViewMatcher(position2)).perform(ViewActions.click())
Assert.assertEquals(R.id.detailFragment, testNavController.currentDestination?.id) 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()) val actualArgs = DetailFragmentArgs.fromBundle(testNavController.backStack.last().arguments ?: Bundle())
Assert.assertEquals(position1, actualArgs.position) Assert.assertEquals(position1, actualArgs.position)
} }

View file

@ -28,17 +28,6 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' 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 // needed for androidTest
packagingOptions { packagingOptions {
@ -56,12 +45,8 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
debugImplementation "androidx.fragment:fragment-testing:1.5.3"
applyAppTestDependenciesTo(this) applyAppTestDependenciesTo(this)
debugImplementation "androidx.fragment:fragment-testing:1.5.3"
testImplementation "androidx.navigation:navigation-testing:$navigation_version" testImplementation project(":examplecase:example-navcontroller-shared-test")
testImplementation project(':test-util-android') androidTestImplementation project(":examplecase:example-navcontroller-shared-test")
androidTestImplementation project(':test-util-android')
androidTestImplementation "androidx.navigation:navigation-testing:$navigation_version"
} }

View file

@ -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()

View file

@ -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()

View file

@ -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
}
}
}
}

View file

@ -21,6 +21,10 @@ project.ext {
applyAppTestDependenciesTo(this) applyAppTestDependenciesTo(this)
applyComposeTestDependenciesTo(this) // if you are using compose applyComposeTestDependenciesTo(this) // if you are using compose
} }
-------------APP-SHARED-TEST(Android Module-------------
dependencies {
applyAppSharedTestDependenciesTo(this)
}
------------------VERSIONS------------------ ------------------VERSIONS------------------
versions try to get the global value, if not found they fall back to some defaults. versions try to get the global value, if not found they fall back to some defaults.
@ -77,18 +81,24 @@ project.ext {
] ]
// ------------------PRIVATE------------------ // ------------------PRIVATE------------------
def applyStandardTestDependenciesTo = { module -> def standardTestDependencies = [
module.dependencies {
// coroutine testing // coroutine testing
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$test_coroutines_version" "org.jetbrains.kotlinx:kotlinx-coroutines-test:$test_coroutines_version",
// mockito, mocking library // 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 // junit5
testImplementation "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version" "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version",
testImplementation "org.junit.jupiter:junit-jupiter-params:$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" 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------------------ // ------------------COMPOSE------------------
applyComposeTestDependenciesTo = { module -> applyComposeTestDependenciesTo = { module ->
module.dependencies { module.dependencies {

View file

@ -8,4 +8,6 @@ include ':test-util-shared-android'
include ':test-util-shared-robolectric' include ':test-util-shared-robolectric'
include ':test-util-android' include ':test-util-android'
include ':test-util-junit5-android' include ':test-util-junit5-android'
include ':app-shared-test'
include ':examplecase:example-navcontroller' include ':examplecase:example-navcontroller'
include ':examplecase:example-navcontroller-shared-test'