From Punched Cards to Prompts
AndroidIntroduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
I’m calling it. We’ve been monitoring the state of testing in the Android world for some time now, waiting for the day when testing would be fully baked into the Android development cycle. Well, that day has finally arrived.
I wrote about setting up unit testing in Android Studio back in January. If you were committed enough to get through the whole post, you’ll remember how tedious the setup was. We knew that better testing tools were in the works—the measures I described in my previous post were just a stopgap.
Today, all of those workarounds are completely unnecessary, thanks to the Android Tools team. Android Studio 1.2, which is currently in beta, removes any need for third-party workarounds or custom hacks to Robolectric. The groundwork was introduced in Android Studio 1.1, which was released back in February. It included an experimental setting to enable unit testing. Last week with the beta release of 1.2, that setting is no longer experimental. It’s baked right in to Android Studio. While the Nerds here at the Ranch are quite surprised that nary a word was mentioned in the release notice for v1.2, unit testing support is here to stay.
Today I’d like to walk through the greatly simplified steps to set up unit testing in Android Studio. I’ll then go back and explain how to transition away from the more complicated approach I described in January.
The unit testing how-to post that accompanied the Android Studio 1.1. release is no longer valid for Android Studio 1.2. The only step we need to take is to select the correct Build Variant Test Artifact:
That’s it! We can now add our test dependencies and get to writing tests. Our build.gradle
file looks like this:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
testCompile 'junit:junit:4.12'
testCompile('org.robolectric:robolectric:3.0-rc2') {
exclude group: 'commons-logging', module: 'commons-logging'
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
}
The keen reader will notice that we’re relying on Robolectric’s current release candidate for v 3.0. We’ve tested this new feature in Android Studio against Robolectric 2.4, and it works as well. However, you will need to use a custom RobolectricTestRunner
(see my prior post). Robolectric provides a nice guide on upgrading from 2.4 to 3.0.
A convenient addition to Robolectric 3.0 is an extension of RobolectricTestRunner
specifically designed for Gradle command line or Android Studio, called RobolectricGradleTestRunner
. We can now annotate our test classes:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 21)
public class MyActivityTest {
@Before
public void setUp() throws Exception {
// setup
}
@Test
public void testSomething() throws Exception {
// test
}
}
Finally, we can run our tests as Gradle Tests from within Android Studio! [Editor’s note: see below for changes in Android Studio.]
That’s all there is to it. Now you have immediate feedback on all passing and failing tests right inside Android Studio.
If you followed my previous post, most of the transition requires removing existing code:
build.gradle
classpath 'com.github.jcandksolutions.gradle:android-unit-test:2.1.1'
build.gradle
:apply plugin: 'android-unit-test'
build.gradle
file:afterEvaluate {
tasks.findByName("assembleDebug").dependsOn("testDebugClasses")
}
RobolectricTestRunner
and use RobolectricGradleTestRunner
:@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, emulateSdk = 21)
public class MyActivityTest { ... }
Can it be all so simple? Yes! Check out Josh Skeen’s demo for a working implementation. It’s time to write some great tests and elevate the quality of your Android apps. Show us how you’re using Robolectric and the new testing support to write great tests.
Updated May 15: Several commenters noted that they had some issues when repeatedly running their tests. Here’s how to avoid the “Test events were not received” error.
We need to have Gradle re-run all of our individual tasks each time we run our tests. This is because Gradle tries to optimize our task by identifying individual subtasks that don’t need to be re-run.
Initial run:
...
:app:compileDebugUnitTestJava
:app:compileDebugUnitTestSources
:app:mockableAndroidJar UP-TO-DATE
:app:assembleDebugUnitTest
...
Re-run:
....
:app:compileDebugUnitTestJava UP-TO-DATE
:app:compileDebugUnitTestSources UP-TO-DATE
:app:mockableAndroidJar UP-TO-DATE
:app:assembleDebugUnitTest UP-TO-DATE
...
Unfortunately, Android Studio needs all of these tasks to be run. Otherwise, it will not know to respond to the running of our tests, and we’ll get a “Test events were not received” warning. We can force Gradle to re-run all tasks by updating our run configurations:
Updated December 2015: Several commenters noted that they had some issues finding the “Run -> Gradle” test option in newer versions of Android Studio. Here’s what’s changed and how to fix it.
Android Studio has merged the JUnit and Gradle test options into just JUnit, so you just need to select Run 'MyActivityTest'
Once you run a test, you’ll probably hit the error:
java.lang.RuntimeException: build/intermediates/bundles/debug/AndroidManifest.xml not found or not a file; it should point to your project's AndroidManifest.xml
All you need to do is update JUnit’s working directory. You can do this per-test or per-project, but I prefer to just do it for all projects as an Android Studio default. Open up Run/Debug Configurations, navigate to Defaults -> JUnit. Then select Configuration tab. Then next to Working directory, select MODULE_DIR.
Nothing else from the initial post needs to change. You’ll still rely on RobolectricGradleTestRunner
.
Introduction When computer programming was young, code was punched into cards. That is, holes were punched into a piece of cardboard in a format...
Jetpack Compose is a declarative framework for building native Android UI recommended by Google. To simplify and accelerate UI development, the framework turns the...
Big Nerd Ranch is chock-full of incredibly talented people. Today, we’re starting a series, Tell Our BNR Story, where folks within our industry share...