Android Testing part 1: Unit testing 0 to 1
Part 1: This article
You have been developing Android apps for a couple of years. You want to start writing tests for but unsure how to start?
Rejoice, this tutorial is here to the rescue!
Make no mistake, the first step is the hardest. I know because I’ve recently gone “from 0 to 1" in unit testing. Now I want you to embark on this fantastic journey and enjoy the success with me.
The important questions
Why write tests?
- Improve and maintain product quality with less QA’s manual effort
- Increase confidence when shipping
- Perform routine checks humans can’t perform, fast
- Help you write better code
Why unit tests first?
- Fast to run
- Easy to write, run and measure coverage
Ok, we want to start unit test our code, how do we start?
- Step 1: Refactor your code from MVC (Model-View-Controller — reads “everything in Activity”) to MVP (Model-View-Presenter — easiest to start with; testing the ViewModel in MVVM (Model-View-ViewModel) is the same as testing the Presenter in MVP, refactoring takes more effort though). That is, separate your (testable) app logics from Android specific (difficult-to-test) stuffs like Activity and Fragment.
- Step 2: Write tests! And run tests (and measure test coverage) and profit :)
You’ll only need to remember 1 thing:
separate your (testable) app logics from Android specific (difficult-to-test) stuffs
Read more about MVP architecture here
The app
The app developed for this tutorial is GitHub Search. I assume that everyone here uses GitHub. Isn’t it awesome that this app let you search all the repositories on GitHub?
This app is definitely not “Foo bar” or “Hello World” kind of app. It’s not bloated with stuffs like RxJava (which you should learn in a separate tutorial) either.
The code
master branch contains MVC code. This is your starting point now and my starting point a year ago (No shame there :D Our apps work fine and our bosses are happy right?)
step-1-mvp branch contains the code after refactoring to MVP. Refactoring your code to MVP (or MVVM + data binding in a later part) separates your testable logics from stuffs that contains little to zero logic, platform specific and very difficult to test such as Activity and Fragment.
step-2-unit-tests branch contains the tests you all been waiting for. These tests may be humble but don’t all great things have small beginnings?
Getting from no unit tests to having some proper unit tests is tough. You’ll be writing hundreds and thousands of tests in no time. What could be more exciting than getting your test coverage increase week by week? Just imagine how proud you would be showing your unit testing success to your fellow Android engineers and employers.
From MVC to MVP
Our big fat MainActivity in its “glorious” MVC form
Our Activity is huge (~70 lines for our very simple screen) this way and the logics are not testable!
Let’s move the logics to its own place, namely the Presenter (and test it yay)!
But first, let establish the contract between the View (our MainActivity) and the Presenter (SearchPresenter) through 2 interfaces:
SearchPresenterContract
defines what the Presenter do — searchGitHubRepos()
in this case
public interface SearchPresenterContract {
void searchGitHubRepos(String searchQuery);
}
SearchViewContract
defines what the View do: displaySearchResults()
and displayError()
public interface SearchViewContract {
void displaySearchResults(@NonNull List<SearchResult> searchResults);
void displayError();
void displayError(String s);
}
Here comes the Presenter:
The “repository” here is the essence of the Data Layer in MVP Architecture. Technically, I’m presenting to you a simplified version of MVP Architecture here. It’s necessary to introduce the repositories in our projects to avoid bloating our presenters — multiple presenters can share the same repository and 1 presenter can call multiple repositories e.g. GitHub repositories, Twitter repositories (for users to follow the authors of the popular GitHub repos for example)
Look at our MainActivity! It’s so much slimmer (~40 lines vs. original ~70 lines), so much cleaner now :D
Write your first unit tests
Unit tests are supposed to be isolated. Therefore, in each test we only want to test 1 class. We need to either stub or mock the external dependencies.
For example, in our SearchPresenterTest (testing SearchPresenter logics), we will mock the Repository and ViewContract here.
When possible, use stubs as they execute faster compared to mocks.
Test the Presenter:
Run your (unit) tests with Android Studio
Right click on the test class or package and select “Run ‘Tests in ‘packagename’’ with coverage” (Coverage is optional of course)
Won’t you look at those green stuffs of satisfaction and 😄? There are nothing quite like the moment you run your tests and they all pass!
Conclusion
The automated testing journey starts here. After reading my article, the hardest part is already over. Now, you should have no excuse to procrastinate your duty to write tests.
I can’t promise writing unit tests will always be easy but I promise it’s going to be worth it.
Any comments, questions or suggestions are welcome. I’ve got a lot more to learn about unit testing Android apps so let’s help each other to improve.
Next Steps
Dependency Injection with Dagger
Learn Dagger by Visualization
Concepts should be the same for other frameworks such as Koin
medium.com
More about Android architectures
For a succinct but clear comparison MVC vs. MVP vs. MVVM checkout Eric Maxwell’s article ;)
P.S. Robolectric and 100% test coverage?
Once you have moved all the logics out of your activities, fragments and views, you can optionally use Robolectric to unit tests those Android-specific classes to achieve 100%. I wouldn’t worry about that until I have perfected your app architectures and tested all your presenters, models and viewmodels though.
Q & A?
Ask me any question in a “Reply”. You can even show your “glorious” code in a snippet or GitHub repo and ask me how to refactor and test your code ;)