diff --git a/docs/html/training/testing/ui-testing/index.jd b/docs/html/training/testing/ui-testing/index.jd index 20422f7b424fd..d660c601d5037 100644 --- a/docs/html/training/testing/ui-testing/index.jd +++ b/docs/html/training/testing/ui-testing/index.jd @@ -72,5 +72,5 @@ Testing UI for a Single App
Learn how to test UI in a single app by using the Espresso testing framework.
Testing UI for Multiple Apps
-
Learn how to test UI in multiple apps by using the UI Automator testing framework
+
Learn how to test UI in multiple apps by using the UI Automator testing framework.
\ No newline at end of file diff --git a/docs/html/training/testing/unit-testing/index.jd b/docs/html/training/testing/unit-testing/index.jd new file mode 100644 index 0000000000000..a35ba80a1faf0 --- /dev/null +++ b/docs/html/training/testing/unit-testing/index.jd @@ -0,0 +1,63 @@ +page.title=Building Effective Unit Tests +page.tags=testing,androidjunitrunner,junit,unit test + +trainingnavtop=true +startpage=true + +@jd:body + +
+
+

+ You should also read +

+ +
+
+ +

Unit tests are the fundamental tests in your app testing strategy. By creating and running unit +tests against your code, you can easily verify that the logic of individual units is correct. +Running unit tests after every build helps you to +quickly catch and fix software regressions introduced by code changes to your app. +

+ +

A unit test generally exercises the functionality of the smallest possible unit of code (which +could be a method, class, or component) in a repeatable way. You should build unit tests when you +need to verify the logic of specific code in your app. For example, if you are unit testing a +class, your test might check that the class is in the right state. Typically, the unit of code +is tested in isolation; your test affects and monitors changes to that unit only. A +mocking framework +can be used to isolate your unit from its dependencies.

+ +

Note: Unit tests are not suitable for testing +complex UI interaction events. Instead, you should use the UI testing frameworks, as described in +Automating UI Tests.

+ +

For testing Android apps, you typically create these types of automated unit tests:

+ + + +

The lessons in this class teach you how to build these types of automated unit tests.

+ +

Lessons

+
+
+Building Local Unit Tests
+
Learn how to build unit tests that run on your local machine.
+
+Building Instrumented Unit Tests
+
Learn how to build unit tests that run on an Android device or emulator.
+
\ No newline at end of file diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd new file mode 100644 index 0000000000000..07f0f739250b3 --- /dev/null +++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd @@ -0,0 +1,250 @@ +page.title=Building Instrumented Unit Tests +page.tags=testing,androidjunitrunner,junit,unit test,mock,instrumentation +trainingnavtop=true + +@jd:body + + +
+
+

Dependencies and Prerequisites

+ + + +

This lesson teaches you to

+ +
    +
  1. Set Up Your Testing Environment
  2. +
  3. Create a Instrumented Unit Test Class
  4. +
  5. Run Instrumented Unit Tests
  6. +
+ +

Try it out

+ + +
+
+ +

+Instrumented unit tests are unit tests that run on physical devices and emulators, instead of +the Java Virtual Machine (JVM) on your local machine. You should create instrumented unit tests +if your tests need access to instrumentation information (such as the target app's +{@link android.content.Context}) or if they require the real implementation of an Android framework +component (such as a {@link android.os.Parcelable} or {@link android.content.SharedPreferences} +object). Using instrumented unit tests also helps to reduce the effort required to write and +maintain mock code. You are still free to use a mocking framework, if you choose, to simulate any +dependency relationships. Instrumented unit tests can take advantage of the Android framework APIs +and supporting APIs, such as the Android Testing Support Library. +

+ +

Set Up Your Testing Environment

+

Before building instrumented unit tests, you must:

+ + + +

Create an Instrumented Unit Test Class

+

+Your instrumented unit test class should be written as a JUnit 4 test class. To learn more about +creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see +Create a Local Unit Test Class. +

+

To create an instrumented JUnit 4 test class, add the {@code @RunWith(AndroidJUnit4.class)} +annotation at the beginning of your test class definition. You also need to specify the + +{@code AndroidJUnitRunner} class +provided in the Android Testing Support Library as your default test runner. This step is described +in more detail in Run Instrumented Unit Tests. +

+ +

The following example shows how you might write an instrumented unit test to test that +the {@link android.os.Parcelable} interface is implemented correctly for the +{@code LogHistory} class:

+ +
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import java.util.List;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(AndroidJUnit4.class)
+public class LogHistoryAndroidUnitTest {
+
+    public static final String TEST_STRING = "This is a string";
+    public static final long TEST_LONG = 12345678L;
+    private LogHistory mLogHistory;
+
+    @Before
+    public void createLogHistory() {
+        mLogHistory = new LogHistory();
+    }
+
+    @Test
+    public void logHistory_ParcelableWriteRead() {
+        // Set up the Parcelable object to send and receive.
+        mLogHistory.addEntry(TEST_STRING, TEST_LONG);
+
+        // Write the data.
+        Parcel parcel = Parcel.obtain();
+        mLogHistory.writeToParcel(parcel, mLogHistory.describeContents());
+
+        // After you're done with writing, you need to reset the parcel for reading.
+        parcel.setDataPosition(0);
+
+        // Read the data.
+        LogHistory createdFromParcel = LogHistory.CREATOR.createFromParcel(parcel);
+        List<Pair<String, Long>> createdFromParcelData = createdFromParcel.getData();
+
+        // Verify that the received data is correct.
+        assertThat(createdFromParcelData.size(), is(1));
+        assertThat(createdFromParcelData.get(0).first, is(TEST_STRING));
+        assertThat(createdFromParcelData.get(0).second, is(TEST_LONG));
+    }
+}
+
+ +

Creating a test suite

+

+To organize the execution of your instrumented unit tests, you can group a collection of test +classes in a test suite class and run these tests together. Test suites can be nested; +your test suite can group other test suites and run all their component test classes together. +

+ +

+A test suite is contained in a test package, similar to the main application package. By +convention, the test suite package name usually ends with the {@code .suite} suffix (for example, +{@code com.example.android.testing.mysample.suite}). +

+ +

+To create a test suite for your unit tests, import the JUnit +{@code RunWith} and +{@code Suite} classes. In your test suite, add the +{@code @RunWith(Suite.class)} and the {@code @Suite.SuitClasses()} annotations. In +the {@code @Suite.SuiteClasses()} annotation, list the individual test classes or test +suites as arguments. +

+ +

+The following example shows how you might implement a test suite called {@code UnitTestSuite} +that groups and runs the {@code CalculatorInstrumentationTest} and +{@code CalculatorAddParameterizedTest} test classes together. +

+ +
+import com.example.android.testing.mysample.CalculatorAddParameterizedTest;
+import com.example.android.testing.mysample.CalculatorInstrumentationTest;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+// Runs all unit tests.
+@RunWith(Suite.class)
+@Suite.SuiteClasses({CalculatorInstrumentationTest.class,
+        CalculatorAddParameterizedTest.class})
+public class UnitTestSuite {}
+
+ +

Run Instrumented Unit Tests

+

+The + + Android Plug-in for Gradle +provides a default directory ({@code src/androidTest/java}) for you to store the instrumented unit +and integration test classes and test suites that you want to run on a device. The plug-in compiles +the test code in that directory and then executes the test app using a test runner class. You must +set the + +{@code AndroidJUnitRunner} class provided in the +Android Testing Support Library +as your default test runner.

+

+ +

To specify + +{@code AndroidJUnitRunner} as the default test instrumentation runner, add the following +setting in your {@code build.gradle} file:

+
+android {
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+}
+
+ +

Running instrumented unit tests from Android Studio

+

+To run instrumented unit tests in your Gradle project from Android Studio: +

+
    +
  1. Open the Build Variants window by clicking the left-hand tab, then set the +test artifact to Android Instrumentation Tests. +
  2. +
  3. In the Project window, drill down to your unit test class or method, then + right-click and run it using the Android Test configuration. +
  4. +
+ +

Android Studio displays the results of the unit test execution in the Run +window.

+ +

Running instrumented unit tests from the command-line

+ +

To run instrumented unit tests in your Gradle project from the command-line, call the + {@code connectedCheck} (or {@code cC}) task:

+ +
+./gradlew cC
+
+ +

You can find the generated HTML test result reports in the +{@code <path_to_your_project>/app/build/outputs/reports/androidTests/connected/} directory, +and the corresponding XML files in the +{@code <path_to_your_project>/app/build/outputs/androidTest-results/connected/} directory.

\ No newline at end of file diff --git a/docs/html/training/testing/unit-testing/local-unit-tests.jd b/docs/html/training/testing/unit-testing/local-unit-tests.jd new file mode 100644 index 0000000000000..421709beaacc3 --- /dev/null +++ b/docs/html/training/testing/unit-testing/local-unit-tests.jd @@ -0,0 +1,302 @@ +page.title=Building Local Unit Tests +page.tags=testing,androidjunitrunner,junit,unit test,mock +trainingnavtop=true + +@jd:body + + +
+
+

Dependencies and Prerequisites

+ + + +

This lesson teaches you to

+ +
    +
  1. Set Up Your Testing Environment
  2. +
  3. Create a Local Unit Test Class
  4. +
  5. Run Local Unit Tests
  6. +
+ +

Try it out

+ + +
+
+ +

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 +Mockito, to fulfill any +dependency relationships.

+ +

Android Plug-in for Gradle +version 1.1.0 and higher allows you to create a source directory ({@code src/test/java}) in your +project to store JUnit tests that you want to run on a local machine. This feature improves your +project organization by letting you group your unit tests together into a single source set. You +can run the tests from Android Studio or the command-line, and the plugin executes them on the +local Java Virtual Machine (JVM) on your development machine.

+ +

Set Up Your Testing Environment

+

Before building local unit tests, you must:

+ + + +

Create a Local Unit Test Class

+

Your local unit test class should be written as a JUnit 4 test class. +JUnit 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.

+ +

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.

+ +

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.

+ +
+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));
+    }
+    ...
+}
+
+ +

To test that components in your app return the expected results, use the + +junit.Assert methods to perform validation checks (or assertions) to compare the state +of the component under test against some expected value. To make tests more readable, you +can use +Hamcrest matchers (such as the {@code is()} and {@code equalTo()} methods) to match the +returned result against the expected result.

+ +

In your JUnit 4 test class, you can use annotations to call out sections in your test code for +special processing, such as:

+ + + +

Mocking Android dependencies

+

+By default, the +Android Plug-in for Gradle 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. +

+

+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 +Mockito 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.

+ +

To add a mock object to your local unit test using this framework, follow this programming model: +

+ +
    +
  1. +Include the Mockito library dependency in your {@code build.gradle} file, as described in +Set Up Your Testing Environment. +
  2. +
  3. 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. +
  4. +
  5. To create a mock object for an Android dependency, add the {@code @Mock} annotation before +the field declaration.
  6. +
  7. 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. +
  8. +
+ +

+The following example shows how you might create a unit test that uses a mock +{@link android.content.Context} object. +

+ +
+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));
+    }
+}
+
+ +

+To learn more about using the Mockito framework, see the +Mockito API reference and the +{@code SharedPreferencesHelperTest} class in the +sample code. +

+ +

Run Local Unit Tests

+

+The Android Plug-in for Gradle provides a default directory ({@code src/test/java}) for you to +store unit test classes that you want to run on a local JVM. The plug-in compiles the test code in +that directory and then executes the test app locally using the default test runner class. +

+

+As with production code, you can create unit tests for a +specific flavor or build type. You should keep unit tests in a test +source tree location that corresponds to your production source tree, such as: + + + + + + + + + + + + + + + + + + +
Path to Production ClassPath to Local Unit Test Class
{@code src/main/java/Foo.java}{@code src/test/java/FooTest.java}
{@code src/debug/java/Foo.java}{@code src/testDebug/java/FooTest.java}
{@code src/myFlavor/java/Foo.java}{@code src/testMyFlavor/java/FooTest.java}
+ +

Running local unit tests from Android Studio

+

+To run local unit tests in your Gradle project from Android Studio: +

+
    +
  1. In the Project window, right click on the project and synchronize your project. +
  2. +
  3. Open the Build Variants window by clicking the left-hand tab, then change the +test artifact to Unit Tests. +
  4. +
  5. In the Project window, drill down to your unit test class or method, then +right-click and run it. +
  6. +
+ +

Android Studio displays the results of the unit test execution in the Run +window.

+ +

Running local unit tests from the command-line

+ +

To run local unit tests in your Gradle project from the command-line, call the {@code test} task +command with the {@code --continue} option.

+ +
+./gradlew test --continue
+
+ +

If there are failing tests, the command will display links to HTML reports (one per build +variant). You can find the generated HTML test result reports in the +{@code <path_to_your_project>/app/build/reports/tests/} directory, and the corresponding XML +files in the {@code <path_to_your_project>/app/build/test-results/} directory.

\ No newline at end of file diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 862663eefa1c6..089739bd002fe 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -1875,6 +1875,24 @@ results." +