One of the golden standard test coverage techniques is mutation testing. The main idea of mutation testing is to perform byte code modifications (mutations) to original Android app source code and then run app unit tests to check if they are strong enough to fail as a result of these mutations. This session discusses mutation testing techniques, and demonstrates PIT as a powerful mutation testing tool for Android apps with Demos.
2. About
More than thirteen years of experience in mobile development.
Apache Open Source Committer.
Author of five technical books.
DeveloperWorks Contributing Author, Medium Android blogger
and DZone MVB.
Technical Speaker (JavaOne, ApacheCon, Geecon, JavaLand,
AnDevCon …etc).
An X-IBMer and Currently a Mobile Software Architect in Viacom
(Nickelodeon).
3. Agenda
Traditional Code Coverage
Jacoco.
Code Coverage Demo.
Current challenges of traditional code
coverage.
Mutation Testing 101.
What and Why PIT?
PIT Android Integration.
Mutation Testing Demo.
What about Kotlin Unit Tests?
Kotlin Unit Tests - PIT Demo.
Quiz.
Q & A.
4. Traditional Code Coverage
Code Coverage represents the amount of source code
which will be executed when test cases run.
In order to measure the amount of tested source code,
there are popular coverage criteria:
–Statement coverage
–Function coverage
–Branch coverage, which represents the amount of branches of
each control structure (such as if) covered.
5. Jacoco
JaCoCo is a free code coverage library for Java.
It includes the popular code coverage metrics: statement
coverage, branch coverage, and method coverage.
6. Code Coverage and Jacoco
Fortunately, JaCoCo is fully Integrated with Gradle.
JaCoCo works fine with Android projects.
In order to configure JaCoCo with Gradle:
–Enable code coverage for the build type(s) that you will be testing
with.
–Apply JaCoCo Gradle plugin.
–Configure JaCoCo with your Java sources.
7. Code Coverage and Jacoco
Sample URL:
https://github.com/hazems/android-demo-app
Demo
8. Challenges
TCC only measure the
amount of executed
code.
TCC does not detect
code faults.
TCC does not show
how strong your unit
tests are.
TCC does not
guarantee that unit tests
will fail, if there is a
change in a logic that
was not asserted
before.
9. Mutation testing 101
Mutation testing is about seeding app source code with faults
(mutations).
After seeding, unit tests then run.
If a unit test fails, then a mutation is killed (and means that your
unit test is strong enough to face this mutation).
If a unit test succeeds, then a mutation is lived (and means that
your unit test needs modification to be stronger).
In mutation testing, the quality of the test can be measured by
the percentage of the killed mutations.
10. Mutation testing 101
Mutations can be for example:
–Negate Conditionals Mutator (<= TO > and < TO >=)
–Increment Mutator (i++ TO i--)
–Invert Negatives Mutator (-I to I)
–Math Mutator (+ to – and – to + and * to / and * to /)
–Return Values Mutator (boolean true to false)
–Void Method Call Mutator (removing call).
11. What and Why PIT?
One of the mutation testing tools for Java.
It has advantages
– Fast to execute (unlike most of the Java mutation testing tools).
– Compatible with:
•Ant and Maven
•Gradle
– Active.
– Provides easy to read test reports.
12. PIT Android Integration
Gradle Plugin for PIT is available:
http://gradle-pitest-plugin.solidsoft.info/
https://github.com/szpak/gradle-pitest-plugin
Gradle Plugin works perfect with Java projects.
However, for Android Gradle projects, you need to use
this fork:
https://github.com/koral--/gradle-pitest-plugin
13. PIT Android Integration
For using PIT in your Android apps, add PIT plugin to
your top-level build.gradle file.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'pl.droidsonroids.gradle:gradle-
pitest-plugin:0.1.3'
}
}
Apply plugin: 'com.android.application’
apply plugin: 'pl.droidsonroids.pitest'
14. PIT Android Integration
Configure PIT plugin basically as follows
pitest {
targetClasses = ['com.test.xyz.demo.ui.weather.vp.*',
'com.test.xyz.demo.ui.repodetails.vp.*',
'com.test.xyz.demo.ui.repolist.vp.*’,
'com.test.xyz.demo.domain.interactor.*']
/* Specify target classes to be mutated */
excludedClasses = ['**Factory*']
/* Exclude the unnecessary classes */
threads = 4
/* Specify number of threads to execute mutation testing */
outputFormats = ['XML', 'HTML']
/* Specify output format */
}
15. PIT Android Integration
Check the mutation results by executing the following
command:
>./gradlew clean pitest
17. What about Kotlin Unit tests?
Fortunately, PI Tests can work perfectly with
Kotlin unit tests.
You can use PI Tests with the most popular
Kotlin unit test libraries:
– Kotlin Mockito.
– Kluent.
19. Kotlin Quiz
class B {
companion object {
var value: Int = 6;
init {
value = value - --value;
}
}
init {
value *= 2;
}
}
fun main(args: Array<String>) {
listOf(B(), B());
print(B.value)
}
20. Q & A
Viacom Android engineering is hiring
now. If you are interested let me know.
Twitter: @hazems
Email: hazem.saleh@viacom.com
Editor's Notes
Hello and welcome everyone
I’m Hazem Saleh, An Android mobile architect in Viacom (Nickelodeon).
Today, I will be talking about effective unit testing for android apps.
Before going into the details of this presentation, I would like to introduce myself in more details.
My name is Hazem Saleh …
So today, we will explore traditional code coverage and how it can be implemented for Android apps with a Demo.
Then we will explore the current challenges of traditional code coverage.
Then we will explore mutation testing, and how it can help in meeting the challenges of traditional code coverage.
Then we will explore PIT tool as an example of mutation testing tools and how we can integrate it with our android apps with Demos.
Finally, we will explore how we can integrate Kotlin unit tests with PIT with demos.
Run the app.
Explain the App MVP Architecture
View -> RepoListFragment / View Interface.
Presenter -> RepoListPresenter / Presenter Interface
Main Interactor.
RepoList end-to-end scenario.
RepoListPresenter Test.
WeatherPresenter Test.
Explain test cases one-by-one.
Run unit tests.
Show how Jacoco is configured.
Run:> ./gradlew clean jacocoTestReportMinimum (20 minutes)>>35 min?
It does not guarantee that unit tests will fail, if there is a change in the logic that was not asserted before.
http://pitest.org/quickstart/mutators/
Show how PIT is configured.
Run:> ./gradlew clean pitest
Fix test cases.
Re-run again.
========
The common causes of tests failing at the coverage stage are
1. PIT picking up tests not included/are excluded in the normal test config
2. Tests rely on an environment variable or other property set in the test config, but not set in the pitest config
3. Tests have a hidden order dependency that is not revealed during the normal test run
4. PIT doesn't like something in your tech stack - possibly a JUnit test runner