Android App Testing. Practical steps

Dmitrii Soldatov
3 min readSep 12, 2019

--

In this post, I’ll show you how we covered our code with tests. But first I’d like to give a brief overview of our app architecture. It is a pretty popular combination of Clean Architecture and MVP with Kotlin and RxJava inside.

  1. Presentation layer implemented with MVP
    includes Android components (Activity, Fragment) as a View and Presenter, responsible for running use cases; also presenter maps business objects (BO) into view models
  2. Domain layer based on RxJava
    use cases are returning basic reactive streams (Completable, Single, Observable); under the hood, they use repositories from the data layer and map data transfer objects(DTO) into BO.
  3. Data layer based on RxJava
    repositories include all methods to manipulate data; they use different kinds of data sources inside (local storage, remote API, system services, etc)

Given … When … Then …

Every test consists of three sections:

  1. Given (conditions)
  2. When (action is taken)
  3. Then (make assertions)

It’s a good practice to separate these sections with a blank line to improve the readability of the test.

You can also use this pattern in the naming of test methods: testGivenNetworkErrorWhenRefreshRequestedThenErrorShouldBeDisplayed (this probably requires team agreement).

Writing tests when you don’t have enough time

When you just created a new feature your test coverage is zero. You need to choose a good starting point to create the most effective tests first.

It’s always better to start with unit tests, as they cover core business logic and can be run on nearly every commit.

Considering you have a typical feature, you will have different layers to be covered with tests.

Here is a suggested order of test writing, from high to low importance:

  1. Use cases and other business logic.
  2. Presenters and their interactions with views, use cases.
  3. Repositories and data source combining logic.
  4. Mappers for DTO-BO and BO-ViewModel transitions.
  5. Simple UI test checking screen opening.
  6. Integration tests working with stub data or real API.
  7. Simple UI test checking basic features of the screen (not checking specific text size, colors, positions, etc).
  8. End to End tests covering user scenarios.

Testing tools

Here are the libraries currently used in our project:

Tip #1

JUnit 4 creates new instance of test class to run each test, so if you need to do some initialization “before class”, make sure you use static members:

class SampleTest {
companion object {

@JvmStatic
lateinit var repository: DataRepository

@BeforeClass
@JvmStatic
fun setup() {
repository = mock(...)
}
}
}

Tip #2

Initializing mocks is an expensive operation. When possible, reset mocks to speed up tests.

class SampleTest {
companion object {

@JvmStatic
lateinit var repository: DataRepository
}


@After
fun reset() {
Mockito.reset(repository)
}
}

--

--