1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
page.title=Building Local Unit Tests
page.tags=testing,androidjunitrunner,junit,unit test,mock
trainingnavtop=true
@jd:body
<!-- This is the training bar -->
<div id="tb-wrapper">
<div id="tb">
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#setup">Set Up Your Testing Environment</a></li>
<li><a href="#build">Create a Local Unit Test Class</a>
<ol>
<li><a href="#mocking-dependencies">Mock Android dependencies</a></li>
</ol>
</li>
<li><a href="#run">Run Local Unit Tests</a></li>
</ol>
<h2>Try it out</h2>
<ul>
<li>
<a href="https://github.com/googlesamples/android-testing/tree/master/unit/BasicSample"
class="external-link">Local Unit Tests Code Samples</a></li>
<li><a href="https://codelabs.developers.google.com/codelabs/android-testing/index.html?index=..%2F..%2Findex#0"
class="external-link">Android Testing Codelab</a></li>
</ul>
</div>
</div>
<p>If your unit test has no dependencies or only has simple dependencies on Android, you should run
your test on a local development machine. This testing approach is efficient because it helps
you avoid the overhead of loading the target app and unit test code onto a physical device or
emulator every time your test is run. Consequently, the execution time for running your unit
test is greatly reduced. With this approach, you normally use a mocking framework, like
<a href="https://github.com/mockito/mockito" class="external-link">Mockito</a>, to fulfill any
dependency relationships.</p>
<h2 id="setup">Set Up Your Testing Environment</h2>
<p>In your Android Studio project, you must store the source files for local
unit tests at <code><var>module-name</var>/src/test/java/</code>. This directory
already exists when you create a new project.</p>
<p>You also need to configure the testing dependencies for your project to use
the standard APIs provided by the JUnit 4 framework. If your test needs to
interact with Android dependencies, include the <a href=
"https://github.com/mockito/mockito" class="external-link">Mockito</a> library
to simplify your local unit tests. To learn more about using mock objects in
your local unit tests, see <a href=
"{@docRoot}training/testing/unit-testing/local-unit-tests.html#mocking-dependencies">
Mocking Android dependencies</a>.</p>
<p>In your app's top-level {@code build.gradle} file, you need to specify these
libraries as dependencies:</p>
<pre>
dependencies {
// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'
// Optional -- Mockito framework
testCompile 'org.mockito:mockito-core:1.10.19'
}
</pre>
<h2 id="build">Create a Local Unit Test Class</h2>
<p>Your local unit test class should be written as a JUnit 4 test class.
<a href="http://junit.org/" class="external-link">JUnit</a> is the most popular
and widely-used unit testing framework for Java. The latest version of this framework, JUnit 4,
allows you to write tests in a cleaner and more flexible way than its predecessor versions. Unlike
the previous approach to Android unit testing based on JUnit 3, with JUnit 4, you do not need to
extend the {@code junit.framework.TestCase} class. You also do not need to prefix your test method
name with the {@code ‘test’} keyword, or use any classes in the {@code junit.framework} or
{@code junit.extensions} package.</p>
<p>To create a basic JUnit 4 test class, create a Java class that contains one or more test methods.
A test method begins with the {@code @Test} annotation and contains the code to exercise
and verify a single functionality in the component that you want to test.</p>
<p>The following example shows how you might implement a local unit test class. The test method
{@code emailValidator_CorrectEmailSimple_ReturnsTrue} verifies that the {@code isValidEmail()}
method in the app under test returns the correct result.</p>
<pre>
import org.junit.Test;
import java.util.regex.Pattern;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class EmailValidatorTest {
@Test
public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
assertThat(EmailValidator.isValidEmail("name@email.com"), is(true));
}
...
}
</pre>
<p>To test that components in your app return the expected results, use the
<a href="http://junit.org/javadoc/latest/org/junit/Assert.html" class="external-link">
junit.Assert</a> methods to perform validation checks (or <em>assertions</em>) to compare the state
of the component under test against some expected value. To make tests more readable, you
can use <a href="https://github.com/hamcrest" class="external-link">
Hamcrest matchers</a> (such as the {@code is()} and {@code equalTo()} methods) to match the
returned result against the expected result.</p>
<h3 id="mocking-dependencies">Mock Android dependencies</h3>
<p>By default, the <a href=
"{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for
Gradle</a> executes your local unit tests against a modified version of the
{@code android.jar} library, which does not contain any actual code. Instead,
method calls to Android classes from your unit test throw an exception. This is
to make sure you test only your code and do not depend on any
particular behavior of the Android platform (that you have not explicitly
mocked).</p>
<p>
You can use a mocking framework to stub out external dependencies in your code, to easily test that
your component interacts with a dependency in an expected way. By substituting Android dependencies
with mock objects, you can isolate your unit test from the rest of the Android system while
verifying that the correct methods in those dependencies are called. The
<a href="https://github.com/mockito/mockito" class="external-link">Mockito</a> mocking framework
for Java (version 1.9.5 and higher) offers compatibility with Android unit testing.
With Mockito, you can configure mock objects to return some specific value when invoked.</p>
<p>To add a mock object to your local unit test using this framework, follow this programming model:
</p>
<ol>
<li>
Include the Mockito library dependency in your {@code build.gradle} file, as described in
<a href="#setup">Set Up Your Testing Environment</a>.
</li>
<li>At the beginning of your unit test class definition, add the
{@code @RunWith(MockitoJUnitRunner.class)} annotation. This annotation tells the Mockito test
runner to validate that your usage of the framework is correct and simplifies the initialization of
your mock objects.
</li>
<li>To create a mock object for an Android dependency, add the {@code @Mock} annotation before
the field declaration.</li>
<li>To stub the behavior of the dependency, you can specify a condition and return
value when the condition is met by using the {@code when()} and {@code thenReturn()} methods.
</li>
</ol>
<p>
The following example shows how you might create a unit test that uses a mock
{@link android.content.Context} object.
</p>
<pre>
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import android.content.SharedPreferences;
@RunWith(MockitoJUnitRunner.class)
public class UnitTestSample {
private static final String FAKE_STRING = "HELLO WORLD";
@Mock
Context mMockContext;
@Test
public void readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
when(mMockContext.getString(R.string.hello_word))
.thenReturn(FAKE_STRING);
ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext);
// ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString();
// ...then the result should be the expected one.
assertThat(result, is(FAKE_STRING));
}
}
</pre>
<p>
To learn more about using the Mockito framework, see the
<a href="http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html"
class="external-link">Mockito API reference</a> and the
{@code SharedPreferencesHelperTest} class in the
<a href="https://github.com/googlesamples/android-testing/tree/master/unit/BasicSample"
class="external-link">sample code</a>.
</p>
<p>If the exceptions thrown by Android APIs in the
<code>android.jar</code> are problematic for your tests, you can change the behavior so that methods
instead return either null or zero by adding the following configuration in your project's
top-level <code>build.gradle</code> file:</p>
<pre>
android {
...
testOptions {
unitTests.returnDefaultValues = true
}
}
</pre>
<p class="caution"><strong>Caution:</strong>
Setting the <code>returnDefaultValues</code> property to <code>true</code>
should be done with care. The null/zero return values can introduce
regressions in your tests, which are hard to debug and might allow failing tests
to pass. Only use it as a last resort.</p>
<h2 id="run">Run Local Unit Tests</h2>
<p>To run your local unit tests, follow these steps:</p>
<ol>
<li>Be sure your project is synchronized with Gradle by clicking
<b>Sync Project</b> <img src="/images/tools/sync-project.png" alt=""
class="inline-icon"> in the toolbar.</li>
<li>Run your test in one of the following ways:
<ul>
<li>To run a single test, open the <b>Project</b> window, and then
right-click a test and click <strong>Run</strong> <img src=
"{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.</li>
<li>To test all methods in a class, right-click a class or method in the
test file and click <b>Run</b> <img src=
"{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
<li>To run all tests in a directory, right-click on the
directory and select <strong>Run tests</strong> <img src=
"{@docRoot}images/tools/as-run.png" alt="" class="inline-icon">.
</li>
</ul>
</li>
</ol>
<p>
The Android Plugin for Gradle compiles the local unit test code located in
the default directory ({@code src/test/java/}), builds a test app, and
executes it locally using the default test runner class. Android Studio then
displays the results in the <b>Run</b> window.
</p>
|