blob: 8221a6dcdb61c98e32582e92c0017e7df23ba778 [file] [log] [blame]
Quddus Chong4bc762a2015-04-07 16:42:24 -07001page.title=Building Local Unit Tests
2page.tags=testing,androidjunitrunner,junit,unit test,mock
3trainingnavtop=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"
29class="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
35your test on a local development machine. This testing approach is efficient because it helps
36you avoid the overhead of loading the target app and unit test code onto a physical device or
37emulator every time your test is run. Consequently, the execution time for running your unit
38test 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
40dependency relationships.</p>
41
42<p><a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a>
43version 1.1.0 and higher allows you to create a source directory ({@code src/test/java}) in your
44project to store JUnit tests that you want to run on a local machine. This feature improves your
45project organization by letting you group your unit tests together into a single source set. You
46can run the tests from Android Studio or the command-line, and the plugin executes them on the
47local 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>
69dependencies {
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
84and widely-used unit testing framework for Java. The latest version of this framework, JUnit 4,
85allows you to write tests in a cleaner and more flexible way than its predecessor versions. Unlike
86the previous approach to Android unit testing based on JUnit 3, with JUnit 4, you do not need to
87extend the {@code junit.framework.TestCase} class. You also do not need to prefix your test method
88name 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 Fuller9498e8a2015-11-30 09:51:33 +000092A test method begins with the {@code @Test} annotation and contains the code to exercise
Quddus Chong4bc762a2015-04-07 16:42:24 -070093and 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()}
97method in the app under test returns the correct result.</p>
98
99<pre>
100import org.junit.Test;
101import java.util.regex.Pattern;
102import static org.junit.Assert.assertFalse;
103import static org.junit.Assert.assertTrue;
104
105public class EmailValidatorTest {
106
107 &#64;Test
108 public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
109 assertThat(EmailValidator.isValidEmail("name&#64;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">
117junit.Assert</a> methods to perform validation checks (or <em>assertions</em>) to compare the state
118of the component under test against some expected value. To make tests more readable, you
119can use <a href="https://code.google.com/p/hamcrest/wiki/Tutorial" class="external-link">
120Hamcrest matchers</a> (such as the {@code is()} and {@code equalTo()} methods) to match the
121returned 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
124special processing, such as:</p>
125
126<ul>
127<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000128{@code @Before}: Use this annotation to specify a block of code with test setup operations. This
129code block will be invoked before each test. You can have multiple {@code @Before} methods but
Quddus Chong4bc762a2015-04-07 16:42:24 -0700130the order which these methods are called is not fixed.
131</li>
132<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000133{@code @After}: This annotation specifies a block of code with test tear-down operations. This
134code block will be called after every test method. You can define multiple {@code @After}
Quddus Chong4bc762a2015-04-07 16:42:24 -0700135operations in your test code. Use this annotation to release any resources from memory.
136</li>
137<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000138{@code @Test}: Use this annotation to mark a test method. A single test class can contain
Quddus Chong4bc762a2015-04-07 16:42:24 -0700139multiple test methods, each prefixed with this annotation.
140</li>
141<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000142{@code @BeforeClass}: Use this annotation to specify static methods to be invoked only once per
Quddus Chong4bc762a2015-04-07 16:42:24 -0700143test class. This testing step is useful for expensive operations such as connecting to a database.
144</li>
145<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000146{@code @AfterClass}: Use this annotation to specify static methods to be invoked only after all
Quddus Chong4bc762a2015-04-07 16:42:24 -0700147tests in the class have been run. This testing step is useful for releasing any resources allocated
Neil Fuller9498e8a2015-11-30 09:51:33 +0000148in the {@code @BeforeClass} block.
Quddus Chong4bc762a2015-04-07 16:42:24 -0700149</li>
150<li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000151{@code @Test(timeout=<milliseconds>)}: Specifies a timeout period for the test. If the
Quddus Chong4bc762a2015-04-07 16:42:24 -0700152test starts but does not complete within the given timeout period, it automatically fails. You must
Neil Fuller9498e8a2015-11-30 09:51:33 +0000153specify the timeout period in milliseconds, for example: {@code @Test(timeout=5000)}.
Quddus Chong4bc762a2015-04-07 16:42:24 -0700154</li>
155</ul>
156
157<h3 id="mocking-dependencies">Mocking Android dependencies</h3>
158<p>
159By default, the <a href="{@docRoot}tools/building/plugin-for-gradle.html">
160Android Plug-in for Gradle</a> executes your local unit tests against a modified
161version of the {@code android.jar} library, which does not contain any actual code. Instead, method
162calls to Android classes from your unit test throw an exception.
163</p>
164<p>
165You can use a mocking framework to stub out external dependencies in your code, to easily test that
166your component interacts with a dependency in an expected way. By substituting Android dependencies
167with mock objects, you can isolate your unit test from the rest of the Android system while
168verifying 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
170for Java (version 1.9.5 and higher) offers compatibility with Android unit testing.
171With 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>
178Include 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 Fuller9498e8a2015-11-30 09:51:33 +0000182{@code @RunWith(MockitoJUnitRunner.class)} annotation. This annotation tells the Mockito test
Quddus Chong4bc762a2015-04-07 16:42:24 -0700183runner to validate that your usage of the framework is correct and simplifies the initialization of
184your mock objects.
185</li>
Neil Fuller9498e8a2015-11-30 09:51:33 +0000186<li>To create a mock object for an Android dependency, add the {@code @Mock} annotation before
Quddus Chong4bc762a2015-04-07 16:42:24 -0700187the field declaration.</li>
188<li>To stub the behavior of the dependency, you can specify a condition and return
189value when the condition is met by using the {@code when()} and {@code thenReturn()} methods.
190</li>
191</ol>
192
193<p>
194The 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>
199import static org.hamcrest.MatcherAssert.assertThat;
200import static org.hamcrest.CoreMatchers.*;
201import static org.mockito.Mockito.*;
202import org.junit.Test;
203import org.junit.runner.RunWith;
204import org.mockito.Mock;
205import org.mockito.runners.MockitoJUnitRunner;
206import android.content.SharedPreferences;
207
208&#64;RunWith(MockitoJUnitRunner.class)
209public class UnitTestSample {
210
211 private static final String FAKE_STRING = "HELLO WORLD";
212
213 &#64;Mock
214 Context mMockContext;
215
216 &#64;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>
233To learn more about using the Mockito framework, see the
234<a href="http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html"
235class="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"
238class="external-link">sample code</a>.
239</p>
240
241<h2 id="run">Run Local Unit Tests</h2>
242<p>
243The Android Plug-in for Gradle provides a default directory ({@code src/test/java}) for you to
244store unit test classes that you want to run on a local JVM. The plug-in compiles the test code in
245that directory and then executes the test app locally using the default test runner class.
246</p>
247<p>
248As with production code, you can create unit tests for a
249<a href="http://developer.android.com/tools/building/configuring-gradle.html#workBuildVariants"
250class="external-link">specific flavor or build type</a>. You should keep unit tests in a test
251source 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>
274To 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
280test 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
283right-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>
288window.</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
293command 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
300variant). You can find the generated HTML test result reports in the
Neil Fuller9498e8a2015-11-30 09:51:33 +0000301{@code <path_to_your_project>/app/build/reports/tests/} directory, and the corresponding XML
302files in the {@code <path_to_your_project>/app/build/test-results/} directory.</p>