III. About the author
22. Flow control and ranges
28.2 Instrumentation tests
Instrumentation tests are a bit different. They are normally used to test UI interac-tions, where we need an Application instance to be running by the time the tests are executed. To do this, we’ll need to deploy the App and run the tests on a device.
This type of tests must be included in theandroidTestfolder, and we must change
‘Test Artifact’ to ‘Android Instrumentation Tests’ in ‘Build Variants’ panel on old
28 Testing your App 170 Android Studio versions. The official library to implement instrumentation tests is Espresso⁵¹, which will help us easily navigate through our App by writingActions, and filter and check results usingViewMatchers andMatchers.
The configuration is a bit harder than the previous one. We need a bunch of extra libraries and Gradle configuration. The good thing is that Kotlin doesn’t add any extra overhead, so if you already know how to configure Espresso, it will be easy for you.
First, specify the test runner indefaultConfig:
1 defaultConfig {
2 ...
3 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
4 }
Once you’ve dealt with the runner, it’s time to add the rest of the dependencies, this time usingandroidTestCompile. That way, these libraries only will be added when we compile to run the instrumentation tests:
1 dependencies { 8 exclude group: 'com.android.support', module: 'appcompat-v7'
9 exclude group: 'com.android.support', module: 'support-v4' 10 exclude group: 'com.android.support', module: 'design'
11 exclude group: 'com.android.support', module: 'recyclerview-v7'
12 }
13 }
I don’t want to spend much time talking about this, but here it is a brief reasoning about why you need these libraries:
• runner: It’s the test runner, the one we specified indefaultConfig.
⁵¹https://google.github.io/android-testing-support-library/
28 Testing your App 171
• rules: Includes some rules that help tests inflate and launch the activities.
We’ll use a rule in our examples.
• espresso-core: the basic features of Espresso, the library that makes instru-ment tests easier.
• espresso-contrib: it adds some extra features, such asRecyclerViewtesting support. We have to exclude some of its dependencies, because we already have them in the project, and tests will crash otherwise.
Let’s now create a simple example. The test will click on the first row of the forecast list, and check that it can find a view with the idR.id.weatherDescription. This view is in the DetailActivity, which means we are testing that we successfully navigated to the detail after clicking on a view inside theRecyclerView.
1 class SimpleInstrumentationTest { 2
3 @get:Rule
4 val activityRule = ActivityTestRule(MainActivity::class.java) 5
6 ...
7 }
We need to create an activity rule, that will instantiate the activity the test will use. In Java, you would annotate the field using@Rule. But as you know, fields and properties are not the same, so if you use just that, the execution will fail because the access to the field inside the property is not public. What you need to do is to annotate the getter. Kotlin allows to do that by specifyinggetorsetbefore the name of the rule.
In this case, just write@get:Rule.
After that, we are ready to create our first test:
28 Testing your App 172
1 @Test fun itemClick_navigatesToDetail() { 2 onView(withId(R.id.forecastList)).perform(
The function is annotated with@Test, the same way we did with unit tests. We can start using Espresso in the body of the test. It first performs a click over the first position of the recycler. Then, it checks that it can find a view with a specific id and that it is an instance ofTextView.
To run the test, you can do the same you did for unit tests: right click over thejava folder belowandroidTest, and choose ‘Run All Tests’. Now, in target device, choose the target you prefer. Click ‘OK’ and then run. You should see how the App is started in your device, and the test clicks on the first position, opens the detail activity and closes the App again.
Now we are going to do a more difficult one. The test will open the overflow from the Toolbar, click onSettingsaction, change the city code and check that theToolbar title has changed to the corresponding one.
1 @Test fun modifyZipCode_changesToolbarTitle() {
2 openActionBarOverflowOrOptionsMenu(activityRule.activity)
8 withToolbarTitle(`is`("San Fernando de Henares (ES)"))))
9 }
What the test exactly does is:
• It first opens the overflow by usingopenActionBarOverflowOrOptionsMenu.
• It then finds a view with theSettingstext, and performs a click on it.
• After that, the settings activity is opened, so it will look for theEditTextand replace the old city code with a new one.
28 Testing your App 173
• It presses the back button. This will save the new value inside the preferences, and close the activity.
• AsonResumeis executed inMainActivity, the request is performed again. This will retrieve the forecast of the new city.
• Last line will check the Toolbar title and see whether it matches with the proper value.
There is not a default matcher to checkToolbartitle, but Espresso is easy to extend, so we can create a new matcher which implements the check:
1 private fun withToolbarTitle(textMatcher: Matcher<CharSequence>): Matcher<Any> = 2 object : BoundedMatcher<Any, Toolbar>(Toolbar::class.java) {
3
4 override fun matchesSafely(toolbar: Toolbar): Boolean { 5 return textMatcher.matches(toolbar.title)
6 }
7
8 override fun describeTo(description: Description) { 9 description.appendText("with toolbar title: ") 10 textMatcher.describeTo(description)
11 }
12 }
The matchesSafely function is the place where the check is done, while the describeTofunction adds some information about the matcher.
This chapter has been specially interesting, because we’ve seen how Kotlin is perfectly compatible with both unit and integration tests and is able to interoperate with the testing libraries.Take a look at the code⁵²and run the tests by yourself.
⁵²https://github.com/antoniolg/Kotlin-for-Android-Developers/tree/chapter-28
29 Extra concepts
Through this book, we’ve talked about most important concepts of Kotlin language.
But we didn’t use some of them when implementing the App, and I wouldn’t want to let them out of these pages. In this chapter, I will review some unrelated features that you could need when you develop your next Android App using Kotlin.