Custom views sometimes they contain logic that is hard to test. This is an
example of an added layer of abstraction on top of a (rather simple) custom view. In this case
the custom view becomes an independent entity which can in theory be placed in any Activity or
Fragment and live and fulfill it's destiny.
This repository shows how to implement a simple custom view with testing in mind, write both unit and UI tests, and execute them.
The example implements a very basic MVP set up with dependency injection (via Dagger). The
point of this repository is neither on MVP itself nor on dependency injection, thus the examples
are kept really simple to avoid adding bloat.
AccountView is a custom view that is capable of displaying an avatar, a notification badge and
a text. The view implements the AccountViewContract.View interface, which defines all entry
points to change the state of the view within the business logic.
AccountViewPresenter implements AccountViewContract.Presenter - in this case the presenter
is really dumb, the only thing it reacts to is onViewAttached which triggers an update of the
current state from an attached AccountDataSource. The fetched Account object is then processed
and the respective functions are invoked on the view.
The application contains two flavors: prod and mock - the purpose of this is to add a new
source set to the mock flavor which will contain the MockActivity as well as an
AndroidManifest.xml (in case you need to add permissions to save logs or screenshots) and
layout files for the different mock scenarios.
The MockActivity is kept pretty simple, it has a public variable for the layout, which is
set as content view in the onCreate method. That's it. The view is supposed to do the rest.
The repository shows two different ways to test this feature. Unit tests and UI tests. Unit tests are in general fast to write and fast to execute, whereas UI tests take more time to be developed and more time to be executed. The unit tests in this repository are kept as verbose as possible. Each unit test has a single responsibility, which makes it easy to spot failures of specific parts of the application later on.
The presenter contains our business logic. It is also completely independent from the Android SDK which allows us to execute unit tests via standard JUnit to verify its behavior.
The unit tests for the view are located in /app/src/test/java/com/.../AccountViewPresenterTest.kt.
They are based on JUnit and Mockito (plus a Mockito-Kotlin connector). Entry points into the
presenter (the AccountDataSource) and exit points into the view (AccountViewContract.View) are
mocked.
UI testing is done via espresso. The UI tests are located in
/app/src/androidTest/.../AccountViewTest.kt. For the AccountView there is a new layout file
in the mock source set (mock_view_account.xml) which contains the view that's going to be
tested.
Before starting the Activity with the ActivityTestRule the mocked data source is prepared to
return a data state that is reflecting the current test situation.
Unit tests: ./gradlew test (the unit tests can be executed on any flavor)
UI tests: ./gradlew connectedMockDebugAndroidTest (the UI tests have to be executed on the mock
flavor, since only this flavor contains our mocked data sources)
This software is released under the Apache License v2.
Copyright 2018 Damian Burke