256 lines
10 KiB
Plaintext
256 lines
10 KiB
Plaintext
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>
|