Better tests with AndroidX’s ActivityScenario in Kotlin — Part 1

Piotr Zawadzki
the-stepstone-group-tech-blog
4 min readJun 11, 2019

With the rise of AndroidX Test library came a unified approach for writing Robolectric and instrumentation tests. Previously, to manage Activity lifecycle we had to use an ActivityTestRule in Android Test Support Library and an ActivityController in Robolectric. Now, there’s a single API for that called ActivityScenario. Also, ActivityTestRule is deprecated now and will be removed in favor of ActivityScenario.

In this article, I’ll show how to use this API in a number of different scenarios in Kotlin.

ActivityScenario — the basics

To get started we need to add AndroidX Core KTX library to our Gradle dependencies e.g.

androidTestImplementation 'androidx.test:core-ktx:X.X.X'

The purpose of this API is briefly described in the official JavaDoc:

ActivityScenario provides APIs to start and drive an Activity’s lifecycle state for testing. It works with arbitrary activities and works consistently across different versions of the Android framework.

ActivityScenario offers a launch() method which accepts either a class reference or an Intent used to launch that Activity. KTX version offers a better alternative in Kotlin though i.e. launchActivity() inline function which can be used as follows:

or with a custom Intent:

Why we might need ActivityScenarioRule

ActivityScenario#launch is very similar to ActivityTestRule#launchActivity method. There is a catch though… When we read the documentation carefully, we can find the following text excerpt:

ActivityScenario does’t clean up device state automatically and may leave the activity keep running after the test finishes. Call close() in your test to clean up the state or use try-with-resources statement. This is optional but highly recommended to improve the stability of your tests.

This is something that ActivityTestRule was doing automatically. Now, instead of using close() or a try-with-resources statement we can also rely on ActivityScenarioRule.

ActivityScenarioRule launches a given activity before the test starts and closes after the test.

You can access to scenario interface via getScenario() method. You may finish your activity manually in your test, it will not cause any problems and this rule does nothing after the test in such cases.

To use it we need to add JUnit KTX extension library e.g.

androidTestImplementation 'androidx.test.ext:junit-ktx:X.X.X'

Now, to launch an Activity with the default Intent we could use:

If our Activity actually requires some Intent extras things can get more complicated though:

What if we wanted to do some setup in our Activity before launching it?

With the current version of ActivityScenarioRule we aren’t able to do that. ActivityScenarioRule launches the Activity before we can get to our test method where we would actually like to do the setup e.g. set some Intent extras.

For this, we need to use ActivityScenario directly and remember to clean up afterwards e.g. in an @After annotated method or with the help of a try-with-resources block.

Option 1: clean up in @After

As methods annotated with @After are executed after each test, we can use such a method to clean up the scenario:

Option 2: clean up with a try-with-resources

Try-with-resources doesn’t look that bad, however we need to wrap most of our test code in a use{} block and, personally, I’ve never been a fan of adding that extra indentation in my code. Ideally, I would want to be able to launch my Activity in a similar fashion as I was able to do with ActivityTestRule.

Option 3: use a custom LazyActivityScenarioRule

With this custom Rule, the previous scenario could be written as such:

Here’s the code for LazyActivityScenarioRule:

I’ve copied the original code from ActivityScenarioRule, Kotlinized it and added some more features to allow for optional launching of Activity on start (turned on by default).

What’s so great about it?

One of the biggest benefits of LazyActivityScenarioRule, in my opinion, is that we can use it as a drop-in replacement for ActivityScenarioRule e.g.

but also use it in the cases where we need to provide different Intent extras as described before. We can also use it when we need to do some setup before launching an Activity even though we’re using the default Intent e.g.

With it we have a single solution that meets all our needs and don’t need to think whether to use a try-with-resource approach in some tests and ActivityScenarioRule in others.

What’s next?

In Part 2 I’ll demonstrate how to use LazyActivityScenarioRule in both Robolectric and instrumentation tests with some more advanced examples. Stay tuned 🤘

Read more about the technologies we use or take an inside look at our organisation & processes. Interested in working at StepStone? Check out our careers page.

--

--

Piotr Zawadzki
the-stepstone-group-tech-blog

Principal Android Developer at Stepstone — passionate about technology, Android geek, photography enthusiast.