diff --git a/README.md b/README.md
index c3a8e46..33d1a72 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# Android testing
+
A collection of samples to showcase various testing types that can be performed on the Android code base.
Following are the different types of testing involved in android.
@@ -12,7 +13,6 @@ Following are the different types of testing involved in android.
## Place of execution
-
| Test | Execution |
|---------------------|-----------------------|
| Unit testing | JVM |
@@ -22,7 +22,9 @@ Following are the different types of testing involved in android.
## Unit testing
-Unit testing usually refers testing a particular units of code totally in isolation with other component to ensure their correctness and functionality.
+
+Unit testing usually refers testing a particular units of code totally in isolation with other component to ensure their
+correctness and functionality.
To bring the isolation we need to seek help on framework like `Mockito` to create stubs, mock, and test doubles.
#### Famous Unit testing frameworks
@@ -33,13 +35,13 @@ To bring the isolation we need to seek help on framework like `Mockito` to creat
| Mockito | Mocking framework for unit tests written in Java |
| Truth | To perform assertions in tests |
-
#### Example
Simple test without mocks
#### System under test
+
```kotlin
data class Email(val value: String?) : Parcelable {
fun isValid(): Boolean {
@@ -47,7 +49,9 @@ data class Email(val value: String?) : Parcelable {
}
}
```
+
#### Test
+
```kotlin
class EmailTest {
@@ -71,12 +75,14 @@ class EmailTest {
}
}
```
+
Simple test with mocks
#### System under test
+
```kotlin
class ProfileViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
@@ -84,15 +90,17 @@ class ProfileViewModel @Inject constructor(
val emailAddress = savedStateHandle.get(BundleArgs.KEY_EMAIL)
}
```
+
#### Test
+
```kotlin
- @Test
- fun `should return email value from saved state handle when email address is read from viewModel`() {
- val savedStateHandleMock = mockk()
- every { savedStateHandleMock[BundleArgs.KEY_EMAIL] } returns "abcd@gmail.com"
- val profileViewModel = ProfileViewModel(savedStateHandleMock)
- assertThat(profileViewModel.emailAddress).isEqualTo("abcd@gmail.com")
- }
+ @Test
+fun `should return email value from saved state handle when email address is read from viewModel`() {
+ val savedStateHandleMock = mockk()
+ every { savedStateHandleMock[BundleArgs.KEY_EMAIL] } returns "abcd@gmail.com"
+ val profileViewModel = ProfileViewModel(savedStateHandleMock)
+ assertThat(profileViewModel.emailAddress).isEqualTo("abcd@gmail.com")
+}
```
@@ -100,6 +108,7 @@ class ProfileViewModel @Inject constructor(
## UI testing
+
UI testing usually refers testing the user interface by simulating user action and verify the behavior of UI elements.
#### Famous UI testing frameworks
@@ -114,14 +123,27 @@ UI testing usually refers testing the user interface by simulating user action a
## Integration testing
+
Integration testing usually refers testing interaction between different components or modules of an application.
#### Integration Testing Frameworks
-| Framework | Description |
-|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Robolectric | To perform android UI/functional testing on JVM without the need for android device |
-| AndroidX test runner | Provides AndroidJUnitRunner which is a JUnit test runner that allows to run instrumented JUnit 4 tests on Android devices, including those using the Espresso, UI Automator, and Compose testing frameworks. |
+| Framework | Description |
+|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Robolectric | To perform android UI/functional testing on JVM without the need for android device.
* Test files are located inside the test folder |
+| AndroidX test runner | Provides AndroidJUnitRunner which is a JUnit test runner that allows to run instrumented JUnit 4 tests on Android devices, including those using the Espresso, UI Automator, and Compose testing frameworks.
* Test files are located inside the androidTest folder. |
+
+### Integration Testing Support
+
+#### Gradle Managed Devices
+
+Gradle Managed Devices offers a way to configure a virtual or real device in Gradle to run the integration test. Since
+the configuration is added to Gradle, it allows Gradle to be aware of the device lifecycle and can start or shut down
+the device as required.
+
+```
+./gradlew testDeviceDebugAndroidTest
+```
#### Reference
@@ -133,7 +155,7 @@ Integration testing usually refers testing interaction between different compone
* https://developer.android.com/training/testing/other-components/ui-automator
* https://martinfowler.com/articles/practical-test-pyramid.html#ProviderTestourTeam
* https://martinfowler.com/bliki/TestDouble.html
-*
+* https://developer.android.com/studio/test/gradle-managed-devices
#### Todo
@@ -147,12 +169,13 @@ Integration testing usually refers testing interaction between different compone
* Regression (a return to a previous and less advanced or worse state, condition, or way of behaving)
Points
-- Unit test --- one element of the software at a time
-- Test Double as the generic term for any kind of pretend object used in place of a real object for testing purposes.
-Keywords
+
+- Unit test --- one element of the software at a time
+- Test Double as the generic term for any kind of pretend object used in place of a real object for testing purposes.
+ Keywords
- collaborators
- SUT
-- DD-style way of writing tests
+- DD-style way of writing tests
- Talking about different test classifications is always difficult.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5fe6295..196e694 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,3 +1,5 @@
+import com.android.build.api.dsl.ManagedVirtualDevice
+
plugins {
id("com.android.application")
kotlin("android")
@@ -54,6 +56,17 @@ android {
unitTests {
isIncludeAndroidResources = true
}
+ managedDevices {
+
+ devices {
+ create("testDevice") {
+ device = "Pixel 6"
+ apiLevel = 34
+ systemImageSource = "aosp"
+ }
+
+ }
+ }
}
}
@@ -95,8 +108,7 @@ dependencies {
androidTestImplementation(libs.truth)
// Regular JUnit dependency
- testImplementation(libs.junit4)
- /* Needed for createAndroidComposeRule and other rules used to perform UI test - here we use robolectric to run ui
+ testImplementation(libs.junit4)/* Needed for createAndroidComposeRule and other rules used to perform UI test - here we use robolectric to run ui
test on jvm */
testImplementation(libs.androidx.compose.ui.test.junit4)
// Needed to run android UI test on JVM instead of on an emulator or device