| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 1 | page.title=Building Local Unit Tests |
| 2 | page.tags=testing,androidjunitrunner,junit,unit test,mock |
| 3 | trainingnavtop=true |
| 4 | |
| 5 | @jd:body |
| 6 | |
| 7 | <!-- This is the training bar --> |
| 8 | <div id="tb-wrapper"> |
| 9 | <div id="tb"> |
| 10 | <h2>Dependencies and Prerequisites</h2> |
| 11 | |
| 12 | <ul> |
| 13 | <li>Android Plug-in for Gradle 1.1.0 or higher</li> |
| 14 | </ul> |
| 15 | |
| 16 | <h2>This lesson teaches you to</h2> |
| 17 | |
| 18 | <ol> |
| 19 | <li><a href="#setup">Set Up Your Testing Environment</a></li> |
| 20 | <li><a href="#build">Create a Local Unit Test Class</a></li> |
| 21 | <li><a href="#run">Run Local Unit Tests</a></li> |
| 22 | </ol> |
| 23 | |
| 24 | <h2>Try it out</h2> |
| 25 | |
| 26 | <ul> |
| 27 | <li> |
| 28 | <a href="https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicSample" |
| 29 | class="external-link">Local Unit Tests Code Samples</a></li> |
| 30 | </ul> |
| 31 | </div> |
| 32 | </div> |
| 33 | |
| 34 | <p>If your unit test has no dependencies or only has simple dependencies on Android, you should run |
| 35 | your test on a local development machine. This testing approach is efficient because it helps |
| 36 | you avoid the overhead of loading the target app and unit test code onto a physical device or |
| 37 | emulator every time your test is run. Consequently, the execution time for running your unit |
| 38 | test is greatly reduced. With this approach, you normally use a mocking framework, like |
| 39 | <a href="https://code.google.com/p/mockito/" class="external-link">Mockito</a>, to fulfill any |
| 40 | dependency relationships.</p> |
| 41 | |
| 42 | <p><a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> |
| 43 | version 1.1.0 and higher allows you to create a source directory ({@code src/test/java}) in your |
| 44 | project to store JUnit tests that you want to run on a local machine. This feature improves your |
| 45 | project organization by letting you group your unit tests together into a single source set. You |
| 46 | can run the tests from Android Studio or the command-line, and the plugin executes them on the |
| 47 | local Java Virtual Machine (JVM) on your development machine. </p> |
| 48 | |
| 49 | <h2 id="setup">Set Up Your Testing Environment</h2> |
| 50 | <p>Before building local unit tests, you must:</p> |
| 51 | |
| 52 | <ul> |
| 53 | <li> |
| 54 | <strong>Set up your project structure.</strong> In your Gradle project, the source code for |
| 55 | the target app that you want to test is typically placed under the {@code app/src/main/java} |
| 56 | folder. The source code for your local unit tests must be placed under the |
| 57 | <code>app/src/test/java</code> folder. |
| 58 | To learn more about setting up your project directory, see |
| 59 | <a href="#run">Run Local Unit Tests</a> and |
| 60 | <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>. |
| 61 | </li> |
| 62 | |
| 63 | <li> |
| 64 | <strong>Specify your Android testing dependencies</strong>. In order to use JUnit 4 and |
| 65 | Mockito with your local unit tests, specify the following libraries in |
| 66 | the {@code build.gradle} file of your Android app module: |
| 67 | |
| 68 | <pre> |
| 69 | dependencies { |
| 70 | // Unit testing dependencies |
| 71 | testCompile 'junit:junit:4.12' |
| 72 | // Set this dependency if you want to use Mockito |
| 73 | testCompile 'org.mockito:mockito-core:1.10.19' |
| 74 | // Set this dependency if you want to use Hamcrest matching |
| 75 | androidTestCompile 'org.hamcrest:hamcrest-library:1.1' |
| 76 | } |
| 77 | </pre> |
| 78 | </li> |
| 79 | </ul> |
| 80 | |
| 81 | <h2 id="build">Create a Local Unit Test Class</h2> |
| 82 | <p>Your local unit test class should be written as a JUnit 4 test class. |
| 83 | <a href="http://junit.org/" class="external-link">JUnit</a> is the most popular |
| 84 | and widely-used unit testing framework for Java. The latest version of this framework, JUnit 4, |
| 85 | allows you to write tests in a cleaner and more flexible way than its predecessor versions. Unlike |
| 86 | the previous approach to Android unit testing based on JUnit 3, with JUnit 4, you do not need to |
| 87 | extend the {@code junit.framework.TestCase} class. You also do not need to prefix your test method |
| 88 | name with the {@code ‘test’} keyword, or use any classes in the {@code junit.framework} or |
| 89 | {@code junit.extensions} package.</p> |
| 90 | |
| 91 | <p>To create a basic JUnit 4 test class, create a Java class that contains one or more test methods. |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 92 | A test method begins with the {@code @Test} annotation and contains the code to exercise |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 93 | and verify a single functionality in the component that you want to test.</p> |
| 94 | |
| 95 | <p>The following example shows how you might implement a local unit test class. The test method |
| 96 | {@code emailValidator_CorrectEmailSimple_ReturnsTrue} verifies that the {@code isValidEmail()} |
| 97 | method in the app under test returns the correct result.</p> |
| 98 | |
| 99 | <pre> |
| 100 | import org.junit.Test; |
| 101 | import java.util.regex.Pattern; |
| 102 | import static org.junit.Assert.assertFalse; |
| 103 | import static org.junit.Assert.assertTrue; |
| 104 | |
| 105 | public class EmailValidatorTest { |
| 106 | |
| 107 | @Test |
| 108 | public void emailValidator_CorrectEmailSimple_ReturnsTrue() { |
| 109 | assertThat(EmailValidator.isValidEmail("name@email.com"), is(true)); |
| 110 | } |
| 111 | ... |
| 112 | } |
| 113 | </pre> |
| 114 | |
| 115 | <p>To test that components in your app return the expected results, use the |
| 116 | <a href="http://junit.org/javadoc/latest/org/junit/Assert.html" class="external-link"> |
| 117 | junit.Assert</a> methods to perform validation checks (or <em>assertions</em>) to compare the state |
| 118 | of the component under test against some expected value. To make tests more readable, you |
| 119 | can use <a href="https://code.google.com/p/hamcrest/wiki/Tutorial" class="external-link"> |
| 120 | Hamcrest matchers</a> (such as the {@code is()} and {@code equalTo()} methods) to match the |
| 121 | returned result against the expected result.</p> |
| 122 | |
| 123 | <p>In your JUnit 4 test class, you can use annotations to call out sections in your test code for |
| 124 | special processing, such as:</p> |
| 125 | |
| 126 | <ul> |
| 127 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 128 | {@code @Before}: Use this annotation to specify a block of code with test setup operations. This |
| 129 | code block will be invoked before each test. You can have multiple {@code @Before} methods but |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 130 | the order which these methods are called is not fixed. |
| 131 | </li> |
| 132 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 133 | {@code @After}: This annotation specifies a block of code with test tear-down operations. This |
| 134 | code block will be called after every test method. You can define multiple {@code @After} |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 135 | operations in your test code. Use this annotation to release any resources from memory. |
| 136 | </li> |
| 137 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 138 | {@code @Test}: Use this annotation to mark a test method. A single test class can contain |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 139 | multiple test methods, each prefixed with this annotation. |
| 140 | </li> |
| 141 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 142 | {@code @BeforeClass}: Use this annotation to specify static methods to be invoked only once per |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 143 | test class. This testing step is useful for expensive operations such as connecting to a database. |
| 144 | </li> |
| 145 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 146 | {@code @AfterClass}: Use this annotation to specify static methods to be invoked only after all |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 147 | tests in the class have been run. This testing step is useful for releasing any resources allocated |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 148 | in the {@code @BeforeClass} block. |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 149 | </li> |
| 150 | <li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 151 | {@code @Test(timeout=<milliseconds>)}: Specifies a timeout period for the test. If the |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 152 | test starts but does not complete within the given timeout period, it automatically fails. You must |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 153 | specify the timeout period in milliseconds, for example: {@code @Test(timeout=5000)}. |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 154 | </li> |
| 155 | </ul> |
| 156 | |
| 157 | <h3 id="mocking-dependencies">Mocking Android dependencies</h3> |
| 158 | <p> |
| 159 | By default, the <a href="{@docRoot}tools/building/plugin-for-gradle.html"> |
| 160 | Android Plug-in for Gradle</a> executes your local unit tests against a modified |
| 161 | version of the {@code android.jar} library, which does not contain any actual code. Instead, method |
| 162 | calls to Android classes from your unit test throw an exception. |
| 163 | </p> |
| 164 | <p> |
| 165 | You can use a mocking framework to stub out external dependencies in your code, to easily test that |
| 166 | your component interacts with a dependency in an expected way. By substituting Android dependencies |
| 167 | with mock objects, you can isolate your unit test from the rest of the Android system while |
| 168 | verifying that the correct methods in those dependencies are called. The |
| 169 | <a href="https://code.google.com/p/mockito/" class="external-link">Mockito</a> mocking framework |
| 170 | for Java (version 1.9.5 and higher) offers compatibility with Android unit testing. |
| 171 | With Mockito, you can configure mock objects to return some specific value when invoked.</p> |
| 172 | |
| 173 | <p>To add a mock object to your local unit test using this framework, follow this programming model: |
| 174 | </p> |
| 175 | |
| 176 | <ol> |
| 177 | <li> |
| 178 | Include the Mockito library dependency in your {@code build.gradle} file, as described in |
| 179 | <a href="#setup">Set Up Your Testing Environment</a>. |
| 180 | </li> |
| 181 | <li>At the beginning of your unit test class definition, add the |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 182 | {@code @RunWith(MockitoJUnitRunner.class)} annotation. This annotation tells the Mockito test |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 183 | runner to validate that your usage of the framework is correct and simplifies the initialization of |
| 184 | your mock objects. |
| 185 | </li> |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 186 | <li>To create a mock object for an Android dependency, add the {@code @Mock} annotation before |
| Quddus Chong | 4bc762a | 2015-04-07 16:42:24 -0700 | [diff] [blame] | 187 | the field declaration.</li> |
| 188 | <li>To stub the behavior of the dependency, you can specify a condition and return |
| 189 | value when the condition is met by using the {@code when()} and {@code thenReturn()} methods. |
| 190 | </li> |
| 191 | </ol> |
| 192 | |
| 193 | <p> |
| 194 | The following example shows how you might create a unit test that uses a mock |
| 195 | {@link android.content.Context} object. |
| 196 | </p> |
| 197 | |
| 198 | <pre> |
| 199 | import static org.hamcrest.MatcherAssert.assertThat; |
| 200 | import static org.hamcrest.CoreMatchers.*; |
| 201 | import static org.mockito.Mockito.*; |
| 202 | import org.junit.Test; |
| 203 | import org.junit.runner.RunWith; |
| 204 | import org.mockito.Mock; |
| 205 | import org.mockito.runners.MockitoJUnitRunner; |
| 206 | import android.content.SharedPreferences; |
| 207 | |
| 208 | @RunWith(MockitoJUnitRunner.class) |
| 209 | public class UnitTestSample { |
| 210 | |
| 211 | private static final String FAKE_STRING = "HELLO WORLD"; |
| 212 | |
| 213 | @Mock |
| 214 | Context mMockContext; |
| 215 | |
| 216 | @Test |
| 217 | public void readStringFromContext_LocalizedString() { |
| 218 | // Given a mocked Context injected into the object under test... |
| 219 | when(mMockContext.getString(R.string.hello_word)) |
| 220 | .thenReturn(FAKE_STRING); |
| 221 | ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext); |
| 222 | |
| 223 | // ...when the string is returned from the object under test... |
| 224 | String result = myObjectUnderTest.getHelloWorldString(); |
| 225 | |
| 226 | // ...then the result should be the expected one. |
| 227 | assertThat(result, is(FAKE_STRING)); |
| 228 | } |
| 229 | } |
| 230 | </pre> |
| 231 | |
| 232 | <p> |
| 233 | To learn more about using the Mockito framework, see the |
| 234 | <a href="http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html" |
| 235 | class="external-link">Mockito API reference</a> and the |
| 236 | {@code SharedPreferencesHelperTest} class in the |
| 237 | <a href="https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicSample" |
| 238 | class="external-link">sample code</a>. |
| 239 | </p> |
| 240 | |
| 241 | <h2 id="run">Run Local Unit Tests</h2> |
| 242 | <p> |
| 243 | The Android Plug-in for Gradle provides a default directory ({@code src/test/java}) for you to |
| 244 | store unit test classes that you want to run on a local JVM. The plug-in compiles the test code in |
| 245 | that directory and then executes the test app locally using the default test runner class. |
| 246 | </p> |
| 247 | <p> |
| 248 | As with production code, you can create unit tests for a |
| 249 | <a href="http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants" |
| 250 | class="external-link">specific flavor or build type</a>. You should keep unit tests in a test |
| 251 | source tree location that corresponds to your production source tree, such as: |
| 252 | |
| 253 | <table> |
| 254 | <tr> |
| 255 | <th>Path to Production Class</th> |
| 256 | <th>Path to Local Unit Test Class</th> |
| 257 | </tr> |
| 258 | <tr> |
| 259 | <td>{@code src/main/java/Foo.java}</td> |
| 260 | <td>{@code src/test/java/FooTest.java}</td> |
| 261 | </tr> |
| 262 | <tr> |
| 263 | <td>{@code src/debug/java/Foo.java}</td> |
| 264 | <td>{@code src/testDebug/java/FooTest.java}</td> |
| 265 | </tr> |
| 266 | <tr> |
| 267 | <td>{@code src/myFlavor/java/Foo.java}</td> |
| 268 | <td>{@code src/testMyFlavor/java/FooTest.java}</td> |
| 269 | </tr> |
| 270 | </table> |
| 271 | |
| 272 | <h3 id="run-from-Android-Studio">Running local unit tests from Android Studio</h3> |
| 273 | <p> |
| 274 | To run local unit tests in your Gradle project from Android Studio: |
| 275 | </p> |
| 276 | <ol> |
| 277 | <li>In the <strong>Project</strong> window, right click on the project and synchronize your project. |
| 278 | </li> |
| 279 | <li>Open the <strong>Build Variants</strong> window by clicking the left-hand tab, then change the |
| 280 | test artifact to <em>Unit Tests</em>. |
| 281 | </li> |
| 282 | <li>In the <strong>Project</strong> window, drill down to your unit test class or method, then |
| 283 | right-click and run it. |
| 284 | </li> |
| 285 | </ol> |
| 286 | |
| 287 | <p>Android Studio displays the results of the unit test execution in the <strong>Run</strong> |
| 288 | window.</p> |
| 289 | |
| 290 | <h3 id="run-from-commandline">Running local unit tests from the command-line</h3> |
| 291 | |
| 292 | <p>To run local unit tests in your Gradle project from the command-line, call the {@code test} task |
| 293 | command with the {@code --continue} option.</p> |
| 294 | |
| 295 | <pre> |
| 296 | ./gradlew test --continue |
| 297 | </pre> |
| 298 | |
| 299 | <p>If there are failing tests, the command will display links to HTML reports (one per build |
| 300 | variant). You can find the generated HTML test result reports in the |
| Neil Fuller | 9498e8a | 2015-11-30 09:51:33 +0000 | [diff] [blame^] | 301 | {@code <path_to_your_project>/app/build/reports/tests/} directory, and the corresponding XML |
| 302 | files in the {@code <path_to_your_project>/app/build/test-results/} directory.</p> |