Draft presentation for CodeMash 2015 on how to Unit Test Android code, without going bald. The topics will cover using Robolectric and Mockito with Junit 4 to provide the backbone frameworks to allow unit testing of Android apps without the need for a device or emulator. Includes links to source code and examples, as well as real world results.
1. Unit Testing Android without Going
Bald!
CodeMash 2015
David Carver
Gplus: +David Carver
Twitter: @kingargyle
https://github.com/NineWorlds/serenity-android
2. What is Unit Testing??
● Issolated tests to a particular class.
● Does not test the functionality of other classes.
● Tests only the public methods.
– May test the protected methods
● Tests the expected output of a method.
3. Android Testing
● Difficult to Unit Test
● Must run on device or emulator
– Emulator slow to start up and execute
– Devices must be connected to CI machines
● Slow startup and execution times.
● Developers do not run the tests as often or do
not even write tests.
● Leading to untested code, and more manual
testing or only Integration tests.
4.
5. Why not just use AndroidTestCase
● Slow and requires an Emulator or Device to
run.
● Can use Android Mocks for Activities and
Services but still requires a device or emulator.
● Requires a separate project for tests.
● Tests and code are not kept together.
● Uses Junit and not Junit 4.
6. What other Options?
● Robotium – Integration / Functional testing
framework that tests from the UI. Not
designed for Unit Testing.
● Calabash – Ruby/Cucumber type framework.
More suited for Integration / Behavior tests.
● UI Automator – Extremely slow. Integration
testing
● MonekyRunner – Integration Testing.
● All of these require a device or emulator to
run.
7. Unit Testing Goals
● Must be fast otherwise developers won't run
them and won't write them.
● Should be written in the same language. Less
learning curve.
● Should integrate with existing tools and IDEs.
● Must provide a fast feedback on the
development cycle.
● Ideally integrate with code coverage tools and
easy integration as part of the build.
8. Rogaine for Android Unit Testing
● Junit 4 – Provides a more modern way to test.
● Mockito
– Mocking Framework
– Can mock concrete classes
– Fluent style API for easy readability and setup
– Can spy on existing methods and classes
● Robolectric – Provides a Mocking Framework
and TestRunner for Android
● Dagger – Dependency Injection Framework
9. Robolectric
● Mocking framework for the Android Platform.
– Provides mock implementations for various
Platform versions.
– Allows Tests to run on the Java VM instead of a
device or emulator.
– Tests run locally
– Feedback cycle is seconds instead of minutes.
– Open Source project with large community
– https://github.com/robolectric/robolectric
10. Mockito
● Mocking Framework that does the heavy lifting
for you.
● doReturn(true).when(mockView).isVisible()
– When the method isVisible is called return true as
the result.
– Mock code never executes real implementations.
● Allows for issolation of the Class/Method
under tests from it's dependencies.
● Helps focus testing to the result of the method
and not testing of other frameworks.
11. Mockito
● View spyView = spy(realView)
● doReturn(true).when(spyView).isVisible()
– When the method isVisible is called return true as
the result.
– Mock code never executes real implementations.
● verify(spyView).isVisible()
– Allows verification that a method is called without
actually calling the underlying code.
– Good for mocking out protected methods that
otherwise aren't accessible.
12. Real World Results
● Selenium Android Driver – extremely slow
● UI Automator – 20 tests – 8 minutes to
execute.
● Robolectric, Mockito, plus RoboGuice –
better, 600 tests, about 8 minutes to execute.
● Robolectric, Mockito, plus Dagger – 1700
tests, 3 minutes to execute.
– Code Coverage using Jacoco – 91%
● Robolectric allows for integration with existing
Technical Debt tools like Sonar.
13.
14. Test Examples
● Simple Junit 4 test
● Robolectric Activity Test
● Robolectric plus Mockito Test – (Views)
● https://github.com/NineWorlds/serenity-
android/tree/master/serenity-app/src/test/java
15. Making your Code Testable
● Avoid Anonymous Inner Classes
– Hard to write unit tests for.
– End up writing Integration Tests
● Try to write classes and methods that follow
the Single Responsibility Principal.
● Listeners should be implemented in their own
Classes, not in Activities!
● Use Dependency Injection
– Allows for easy injection of Mocks for tests
● Activities should just be lifecycle managers
16. Conclusion
● Robolectric does not replace Integration or
Functional Tests.
● Robotium and UI Automator still have their
places.
● DO NOT Use Robolectric as an Integration
Test platform it is a Mocking Framework.
● Use Robolectric.buildActivity() sparingly. Has
high startup overhead.
● Mockito can mock anything in the Android
Framework, but may have large number of
mocks.
17. Conclusion
● Running tests locally is 10 times faster and
productive than running tests on a device.
● The more tests the less likely you are to have
critical bugs slip through.
● If you get a bug...WRITE A TEST FOR IT.
● Provides a regression test suite when multiple
developers are working on the code.
● Lets you keep what little hair you may have
left.