Skip to content

Commit

Permalink
Use Gradle Managed Devices to run instrumented test on gradle configu…
Browse files Browse the repository at this point in the history
…red device
  • Loading branch information
sridhar-sp committed Mar 10, 2024
1 parent d039368 commit 5c2af62
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 21 deletions.
61 changes: 42 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -12,7 +13,6 @@ Following are the different types of testing involved in android.

## Place of execution


| Test | Execution |
|---------------------|-----------------------|
| Unit testing | JVM |
Expand All @@ -22,7 +22,9 @@ Following are the different types of testing involved in android.
<hr/>

## 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
Expand All @@ -33,21 +35,23 @@ 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

<details>
<summary>Simple test without mocks</summary>

#### System under test

```kotlin
data class Email(val value: String?) : Parcelable {
fun isValid(): Boolean {
return if (value == null) false else PatternsCompat.EMAIL_ADDRESS.matcher(value).matches()
}
}
```

#### Test

```kotlin
class EmailTest {

Expand All @@ -71,35 +75,40 @@ class EmailTest {
}
}
```

</details>

<details>
<summary>Simple test with mocks</summary>

#### System under test

```kotlin
class ProfileViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
val emailAddress = savedStateHandle.get<String>(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<SavedStateHandle>()
every<String?> { savedStateHandleMock[BundleArgs.KEY_EMAIL] } returns "[email protected]"
val profileViewModel = ProfileViewModel(savedStateHandleMock)
assertThat(profileViewModel.emailAddress).isEqualTo("[email protected]")
}
@Test
fun `should return email value from saved state handle when email address is read from viewModel`() {
val savedStateHandleMock = mockk<SavedStateHandle>()
every<String?> { savedStateHandleMock[BundleArgs.KEY_EMAIL] } returns "[email protected]"
val profileViewModel = ProfileViewModel(savedStateHandleMock)
assertThat(profileViewModel.emailAddress).isEqualTo("[email protected]")
}
```

</details>

<hr/>

## 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
Expand All @@ -114,14 +123,27 @@ UI testing usually refers testing the user interface by simulating user action a
<hr/>

## 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.<br/> * 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. <br/> * 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
```
<hr/>

#### Reference
Expand All @@ -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

<hr/>
#### Todo
Expand All @@ -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.

<hr/>
Expand Down
16 changes: 14 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import com.android.build.api.dsl.ManagedVirtualDevice

plugins {
id("com.android.application")
kotlin("android")
Expand Down Expand Up @@ -54,6 +56,17 @@ android {
unitTests {
isIncludeAndroidResources = true
}
managedDevices {

devices {
create<ManagedVirtualDevice>("testDevice") {
device = "Pixel 6"
apiLevel = 34
systemImageSource = "aosp"
}

}
}
}
}

Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5c2af62

Please sign in to comment.