/android-test

A collection of samples to showcase various testing types that can be performed on the Android code base.

Primary LanguageKotlinApache License 2.0Apache-2.0

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.

  • Unit testing
  • UI testing
  • Integration testing
  • Performance testing

Place of execution

Test Execution
Unit testing JVM
UI testing JVM or Android device
Integration testing Android device

Unit testing

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

Framework Description
Junit Testing framework for Java
Mockito Mocking framework for unit tests written in Java
Truth To perform assertions in tests

Example

Simple test without mocks

System under test

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

Test

class EmailTest {

    @Test
    fun shouldReturnIsValidAsFalseWhenEmailIsNull() {
        Truth.assertThat(Email(null).isValid()).isFalse()
    }

    @Test
    fun shouldReturnIsValidAsFalseWhenEmailIsInvalid() {
        Truth.assertThat(Email("aa@.com").isValid()).isFalse()
        Truth.assertThat(Email("aacd@aa.com@").isValid()).isFalse()
        Truth.assertThat(Email("").isValid()).isFalse()
        Truth.assertThat(Email("@gmail.com").isValid()).isFalse()
    }

    @Test
    fun shouldReturnIsValidAsTrueWhenEmailIsValid() {
        Truth.assertThat(Email("abcd@domain.com").isValid()).isTrue()
        Truth.assertThat(Email("a@domain.in").isValid()).isTrue()
    }
}
Simple test with mocks

System under test

class ProfileViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
) : ViewModel() {
    val emailAddress = savedStateHandle.get<String>(BundleArgs.KEY_EMAIL)
}

Test

    @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 "abcd@gmail.com"
    val profileViewModel = ProfileViewModel(savedStateHandleMock)
    assertThat(profileViewModel.emailAddress).isEqualTo("abcd@gmail.com")
}

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

Framework Description
Espresso Android UI test framework to perform UI interaction and state assertion. (White box testing)
UI Automator To perform cross-app functional UI testing across system and installed apps. (Both Black box & white box testing)
Compose UI test Junit To provide Junit rules invoke composable function in Junit. also provides APIs to perform UI interaction and state assertion.
Appium *Yet to add *

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.
* 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.

Setup

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

    }
  }
}

Run

./gradlew testDeviceDebugAndroidTest

Reference


Todo

  • Screenshot test
  • Small brief on junit rules, test apk
  • Mock vs Stub
  • Difference between AndroidJunitRunner and RobolectricTestRunner
  • Example to Replace a binding in a single test
  • Different types smoke testing
    • Smoke
    • 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
  • collaborators
  • SUT
  • DD-style way of writing tests
  • Talking about different test classifications is always difficult.

Commands ./gradlew connectedAndroidTest --continue ./gradlew testDebugUnitTest