From 2ef3952d8e62b71baca176b3e17315a37facd34a Mon Sep 17 00:00:00 2001
From: quddusc In order to verify that there are no regressions in the layout design and
+functional behavior in your application, it's important to
+create a test for each {@link android.app.Activity} in your application. For
+each test, you need to create the individual parts of a test case, including
+the test fixture, preconditions test method, and {@link android.app.Activity}
+test methods. You can then run your test to get a test report. If any test
+method fails, this might indicate a potential defect in your code. Note: In the Test-Driven Development (TDD)
+approach, instead of writing most or all of your app code up-front and then
+running tests later in the development cycle, you would progressively write
+just enough production code to satisfy your test dependencies, update your
+test cases to reflect new functional requirements, and iterate repeatedly this
+way. {@link android.app.Activity} tests are written in a structured way.
+Make sure to put your tests in a separate package, distinct from the code under
+test. By convention, your test package name should follow the same name as the
+application package, suffixed with ".tests". In the test package
+you created, add the Java class for your test case. By convention, your test case
+name should also follow the same name as the Java or Android class that you
+want to test, but suffixed with “Test”. To create a new test case in Eclipse: A test fixture consists of objects that must be initialized for
+running one or more tests. To set up the test fixture, you can override the
+{@link junit.framework.TestCase#setUp()} and
+{@link junit.framework.TestCase#tearDown()} methods in your test. The
+test runner automatically runs {@link junit.framework.TestCase#setUp()} before
+running any other test methods, and {@link junit.framework.TestCase#tearDown()}
+at the end of each test method execution. You can use these methods to keep
+the code for test initialization and clean up separate from the tests methods.
+ To set up your test fixture in Eclipse: For example:This lesson teaches you to
+
+
+You should also read
+
+
+Create a Test Case
+
+
+
+Set Up Your Test Fixture
+
+
+public class MyFirstTestActivityTest
+ extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
+
+
For example:
+
+public class MyFirstTestActivityTest
+ extends ActivityInstrumentationTestCase2<MyFirstTestActivity> {
+
+ private MyFirstTestActivity mFirstTestActivity;
+ private TextView mFirstTestText;
+
+ public MyFirstTestActivityTest() {
+ super(MyFirstTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mFirstTestActivity = getActivity();
+ mFirstTestText =
+ (TextView) mFirstTestActivity
+ .findViewById(R.id.my_first_test_text_view);
+ }
+}
+
+The constructor is invoked by the test runner to instantiate the test +class, while the {@link junit.framework.TestCase#setUp()} method is invoked by +the test runner before it runs any tests in the test class.
+ + + +Typically, in the {@link junit.framework.TestCase#setUp()} method, you +should:
+You can use the +{@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to +get a reference to the {@link android.app.Activity} under test.
+ +As a sanity check, it is good practice to verify that the test fixture has +been set up correctly, and the objects that you want to test have been correctly +instantiated or initialized. That way, you won’t have to see +tests failing because something was wrong with the setup of your test fixture. +By convention, the method for verifying your test fixture is called +{@code testPreconditions()}.
+ +For example, you might want to add a {@code testPreconditons()} method like +this to your test case:
+ +
+public void testPreconditions() {
+ assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity);
+ assertNotNull(“mFirstTestText is null”, mFirstTestText);
+}
+
+
+The assertion methods are from the JUnit {@link junit.framework.Assert} +class. Generally, you can use assertions to +verify if a specific condition that you want to test is true. +
In both cases, the test runner proceeds to run the other test methods in the +test case.
+ +Next, add one or more test methods to verify the layout and functional +behavior of your {@link android.app.Activity}.
+For example, if your {@link android.app.Activity} includes a +{@link android.widget.TextView}, you can add a test method like this to check +that it has the correct label text:
+
+public void testMyFirstTestTextView_labelText() {
+ final String expected =
+ mFirstTestActivity.getString(R.string.my_first_test);
+ final String actual = mFirstTestText.getText().toString();
+ assertEquals(expected, actual);
+}
+
+
+The {@code testMyFirstTestTextView_labelText()} method simply checks that the +default text of the {@link android.widget.TextView} that is set by the layout +is the same as the expected text defined in the {@code strings.xml} resource.
+Note: When naming test methods, you can use +an underscore to separate what is being tested from the specific case being +tested. This style makes it easier to see exactly what cases are being tested.
+When doing this type of string value comparison, it’s good practice to read +the expected string from your resources, instead of hardcoding the string in +your comparison code. This prevents your test from easily breaking whenever the +string definitions are modified in the resource file.
+To perform the comparison, pass both the expected and actual strings as +arguments to the +{@link junit.framework.Assert#assertEquals(java.lang.String, java.lang.String) assertEquals()} +method. If the values are not the same, the assertion will throw an +{@link junit.framework.AssertionFailedError} exception.
+If you added a {@code testPreconditions()} method, put your test methods +after the {@code testPreconditions()} definition in your Java class.
+For a complete test case example, take a look at +{@code MyFirstTestActivityTest.java} in the sample app.
+ +You can build and run your test easily from the Package Explorer in +Eclipse.
+To build and run your test:
+For example, if the test case passes with no errors, the result should look +like this:
+
++ Figure 1. Result of a test with no errors. +
+ + + diff --git a/docs/html/training/activity-testing/activity-functional-testing.jd b/docs/html/training/activity-testing/activity-functional-testing.jd new file mode 100644 index 000000000000..7c8ff1d7bdd7 --- /dev/null +++ b/docs/html/training/activity-testing/activity-functional-testing.jd @@ -0,0 +1,166 @@ +page.title=Creating Functional Tests +trainingnavtop=true +@jd:body + + +AndroidTestingFun.zip
+Functional testing involves verifying that individual application +components work together as expected by the user. For example, you can create a +functional test to verify that an {@link android.app.Activity} correctly +launches a target {@link android.app.Activity} when the user performs a UI +interaction.
+ +To create a functional test for your {@link android.app.Activity}, your test +class should extend {@link android.test.ActivityInstrumentationTestCase2}. +Unlike {@link android.test.ActivityUnitTestCase}, +tests in {@link android.test.ActivityInstrumentationTestCase2} can +communicate with the Android system and send keyboard input and click events to +the UI.
+ +For a complete test case example, take a look at +{@code SenderActivityTest.java} in the sample app.
+ +Your functional testing goals might include:
+You might implement your test method like this:
+ +
+@MediumTest
+public void testSendMessageToReceiverActivity() {
+ final Button sendToReceiverButton = (Button)
+ mSenderActivity.findViewById(R.id.send_message_button);
+
+ final EditText senderMessageEditText = (EditText)
+ mSenderActivity.findViewById(R.id.message_input_edit_text);
+
+ // Set up an ActivityMonitor
+ ...
+
+ // Send string input value
+ ...
+
+ // Validate that ReceiverActivity is started
+ ...
+
+ // Validate that ReceiverActivity has the correct data
+ ...
+
+ // Remove the ActivityMonitor
+ ...
+}
+
+The test waits for an {@link android.app.Activity} that matches this monitor, +otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was +started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} +that you set +up earlier receives a hit. You can use the assertion methods to verify that +the {@code ReceiverActivity} is indeed started, and that the hit count on the +{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented +as expected.
+ +To monitor a single {@link android.app.Activity} in your application, you +can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}. +The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is +notified by the system whenever an {@link android.app.Activity} that matches your criteria is started. +If a match is found, the monitor’s hit count is updated.
+Generally, to use an +{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:
+For example:
+
+// Set up an ActivityMonitor
+ActivityMonitor receiverActivityMonitor =
+ getInstrumentation().addMonitor(ReceiverActivity.class.getName(),
+ null, false);
+
+// Validate that ReceiverActivity is started
+TouchUtils.clickView(this, sendToReceiverButton);
+ReceiverActivity receiverActivity = (ReceiverActivity)
+ receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS);
+assertNotNull("ReceiverActivity is null", receiverActivity);
+assertEquals("Monitor for ReceiverActivity has not been called",
+ 1, receiverActivityMonitor.getHits());
+assertEquals("Activity is of wrong type",
+ ReceiverActivity.class, receiverActivity.getClass());
+
+// Remove the ActivityMonitor
+getInstrumentation().removeMonitor(receiverActivityMonitor);
+
+
+If your {@link android.app.Activity} has an {@link android.widget.EditText} +field, you might want to test that users can enter values into the +{@link android.widget.EditText} object.
+Generally, to send a string input value to an {@link android.widget.EditText} +object in {@link android.test.ActivityInstrumentationTestCase2}, you should:
+For example:
+
+// Send string input value
+getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ senderMessageEditText.requestFocus();
+ }
+});
+getInstrumentation().waitForIdleSync();
+getInstrumentation().sendStringSync("Hello Android!");
+getInstrumentation().waitForIdleSync();
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/training/activity-testing/activity-ui-testing.jd b/docs/html/training/activity-testing/activity-ui-testing.jd
new file mode 100644
index 000000000000..644f3ca51513
--- /dev/null
+++ b/docs/html/training/activity-testing/activity-ui-testing.jd
@@ -0,0 +1,216 @@
+page.title=Testing UI Components
+trainingnavtop=true
+
+@jd:body
+
+
+AndroidTestingFun.zip
+Typically, your {@link android.app.Activity} includes user interface +components (such as buttons, editable text fields, checkboxes, and pickers) to +allow users to interact with your Android application. This lesson shows how +you can test an {@link android.app.Activity} with a simple push-button UI. You +can use the same general steps to test other, more sophisticated types of UI +components.
+ +Note: The type of UI testing in this lesson is +called white-box testing because you have the +source code for the application that you want to test. The Android +Instrumentation +framework is suitable for creating white-box tests for UI components within an +application. An alternative type of UI testing is black-box testing, +where you may not have access to the application source. This type of testing +is useful when you want to test how your app interacts with other apps or with +the system. Black-box testing is not covered in this training. To learn more +about how to perform black-box testing on your Android apps, see the +UI Testing guide. +
For a complete test case example, take a look at +{@code ClickFunActivityTest.java} in the sample app.
+ +When testing an {@link android.app.Activity} that has a user interface (UI), +the {@link android.app.Activity} under test runs in the UI thread. However, the +test application itself runs in a separate thread in the same process as the +application under test. This means that your test app can reference objects +from the UI thread, but if it attempts to change properties on those objects or +send events to the UI thread, you will usually get a {@code WrongThreadException} +error.
+To safely inject {@link android.content.Intent} objects into your +{@link android.app.Activity} or run test methods on the UI thread, you can +extend your test class to use {@link android.test.ActivityInstrumentationTestCase2}. +To learn more about how to run test methods on the UI thread, see +Testing +on the UI thread.
+ +When setting up the test fixture for UI testing, you should specify the +touch mode +in your {@link junit.framework.TestCase#setUp()} method. Setting the touch mode +to {@code true} prevents the UI control from taking focus when you click it +programmatically in the test method later (for example, a button UI will just +fire its on-click listener). Make sure that you call +{@link android.test.ActivityInstrumentationTestCase2#setActivityInitialTouchMode(boolean) setActivityInitialTouchMode()} +before calling {@link android.test.ActivityInstrumentationTestCase2#getActivity()}. +
+For example: +
+public class ClickFunActivityTest + extends ActivityInstrumentationTestCase2+ +{ + ... + @Override + protected void setUp() throws Exception { + super.setUp(); + + setActivityInitialTouchMode(true); + + mClickFunActivity = getActivity(); + mClickMeButton = (Button) + mClickFunActivity + .findViewById(R.id.launch_next_activity_button); + mInfoTextView = (TextView) + mClickFunActivity.findViewById(R.id.info_text_view); + } +} +
Your UI testing goals might include:
+The following section demonstrates how you can implement test methods +to perform these verifications.
+ +You might add a test method like this to verify that a button is displayed +correctly in your {@link android.app.Activity}:
+
+@MediumTest
+public void testClickMeButton_layout() {
+ final View decorView = mClickFunActivity.getWindow().getDecorView();
+
+ ViewAsserts.assertOnScreen(decorView, mClickMeButton);
+
+ final ViewGroup.LayoutParams layoutParams =
+ mClickMeButton.getLayoutParams();
+ assertNotNull(layoutParams);
+ assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT);
+ assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT);
+}
+
+
+In the {@link android.test.ViewAsserts#assertOnScreen(android.view.View,android.view.View) assertOnScreen()} +method call, you should pass in the root view and the view that you are +expecting to be present on the screen. If the expected view is not found in the +root view, the assertion method throws an {@link junit.framework.AssertionFailedError} +exception, otherwise the test passes.
+You can also verify that the layout of a {@link android.widget.Button} is +correct by getting a reference to its {@link android.view.ViewGroup.LayoutParams} +object, then call assertion methods to verify that the +{@link android.widget.Button} object's width and height attributes match the +expected values.
+The {@code @MediumTest} annotation specifies how the test is categorized, +relative to its absolute execution time. To learn more about using test size +annotations, see Apply Test Annotations.
+ +You might add a test method like this to verify that a +{@link android.widget.TextView} initially appears hidden in +your {@link android.app.Activity}:
+
+@MediumTest
+public void testInfoTextView_layout() {
+ final View decorView = mClickFunActivity.getWindow().getDecorView();
+ ViewAsserts.assertOnScreen(decorView, mInfoTextView);
+ assertTrue(View.GONE == mInfoTextView.getVisibility());
+}
+
+You can call {@link android.view.Window#getDecorView()} to get a reference +to the decor view for the {@link android.app.Activity}. The decor view is the +top-level ViewGroup ({@link android.widget.FrameLayout}) view in the layout +hierarchy.
+ +You can use a test method like this to verify that a +{@link android.widget.TextView} becomes visible when a +{@link android.widget.Button} is pushed:
+ +
+@MediumTest
+public void testClickMeButton_clickButtonAndExpectInfoText() {
+ String expectedInfoText = mClickFunActivity.getString(R.string.info_text);
+ TouchUtils.clickView(this, mClickMeButton);
+ assertTrue(View.VISIBLE == mInfoTextView.getVisibility());
+ assertEquals(expectedInfoText, mInfoTextView.getText());
+}
+
+
+To programmatically click a {@link android.widget.Button} in your +test, call {@link android.test.TouchUtils#clickView(android.test.InstrumentationTestCase,android.view.View) clickView()}. +You must pass in a reference to the test case that is being run and a reference +to the {@link android.widget.Button} to manipulate.
+ +Note: The {@link android.test.TouchUtils} +helper class provides convenience methods for simulating touch interactions +with your application. You can use these methods to simulate clicking, tapping, +and dragging of Views or the application screen.
+Caution: The {@link android.test.TouchUtils} +methods are designed to send events to the UI thread safely from the test thread. +You should not run {@link android.test.TouchUtils} directly in the UI thread or +any test method annotated with {@code @UIThread}. Doing so might +raise the {@code WrongThreadException}.
+ +The following annotations can be applied to indicate the size of a test +method:
+Typically, a short running test that take only a few milliseconds should be +marked as a {@code @SmallTest}. Longer running tests (100 milliseconds or +more) are usually marked as {@code @MediumTest}s or {@code @LargeTest}s, +depending on whether the test accesses resources on the local system only or +remote resources over a network. For guidance on using test size annotations, +see this Android Tools Protip.
+You can mark up your test methods with other test annotations to control +how the tests are organized and run. For more information on other annotations, +see the {@link java.lang.annotation.Annotation} class reference.
+ + + + diff --git a/docs/html/training/activity-testing/activity-unit-testing.jd b/docs/html/training/activity-testing/activity-unit-testing.jd new file mode 100644 index 000000000000..74dcda90b18d --- /dev/null +++ b/docs/html/training/activity-testing/activity-unit-testing.jd @@ -0,0 +1,134 @@ +page.title=Creating Unit Tests +trainingnavtop=true +@jd:body + + +An {@link android.app.Activity} unit test is an excellent way to quickly +verify the state of an {@link android.app.Activity} and its interactions with +other components in isolation (that is, disconnected from the rest of the +system). A unit test generally tests the smallest possible unit of code +(which could be a method, class, or component), without dependencies on system +or network resources. For example, you can write a unit test to check +that an {@link android.app.Activity} has the correct layout or that it +triggers an {@link android.content.Intent} object correctly.
+Unit tests are generally not suitable for testing complex UI interaction +events with the system. Instead, you should use +the {@link android.test.ActivityInstrumentationTestCase2} class, as described +in Testing UI Components.
+This lesson shows how you can write a unit test to verify that an +{@link android.content.Intent} is triggered to launch another +{@link android.app.Activity}. +Since the test runs in an isolated environment, the +{@link android.content.Intent} +is not actually sent to the Android system, but you can inspect that the +{@link android.content.Intent} object's payload data is accurate.
+For a complete test case example, take a look at +{@code LaunchActivityTest.java} in the sample app.
+ +Note: To test against system or external +dependencies, you can use mock objects from a mocking +framework and inject them into your unit tests. To learn more about the mocking +framework provided by Android, see +Mock +Object Classes.
+ +The {@link android.test.ActivityUnitTestCase} class provides support for +isolated testing of a single {@link android.app.Activity}. To create a unit +test for your {@link android.app.Activity}, your test class should extend +{@link android.test.ActivityUnitTestCase}.
+ +The {@link android.app.Activity} in an {@link android.test.ActivityUnitTestCase} +is not automatically started by Android Instrumentation. To start the +{@link android.app.Activity} in isolation, you need to explicitly call the +{@link android.test.ActivityUnitTestCase#startActivity(android.content.Intent, android.os.Bundle, java.lang.Object) startActivity()} +method, and pass in the {@link android.content.Intent} to +launch your target {@link android.app.Activity}.
+ +For example:
+
+public class LaunchActivityTest
+ extends ActivityUnitTestCase<LaunchActivity> {
+ ...
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mLaunchIntent = new Intent(getInstrumentation()
+ .getTargetContext(), LaunchActivity.class);
+ startActivity(mLaunchIntent, null, null);
+ final Button launchNextButton =
+ (Button) getActivity()
+ .findViewById(R.id.launch_next_activity_button);
+ }
+}
+
+
+Your unit testing goals might include:
+To verify if an {@link android.content.Intent} was triggered +following the {@link android.widget.Button} click, you can use the +{@link android.test.ActivityUnitTestCase#getStartedActivityIntent()} method. +By using assertion methods, you can verify that the returned +{@link android.content.Intent} is not null, and that it contains the expected +string value to launch the next {@link android.app.Activity}. If both assertions +evaluate to {@code true}, you've successfully verified that the +{@link android.content.Intent} was correctly sent by your +{@link android.app.Activity}.
+ +You might implement your test method like this:
+
+@MediumTest
+public void testNextActivityWasLaunchedWithIntent() {
+ startActivity(mLaunchIntent, null, null);
+ final Button launchNextButton =
+ (Button) getActivity()
+ .findViewById(R.id.launch_next_activity_button);
+ launchNextButton.performClick();
+
+ final Intent launchIntent = getStartedActivityIntent();
+ assertNotNull("Intent was null", launchIntent);
+ assertTrue(isFinishCalled());
+
+ final String payload =
+ launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY);
+ assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD, payload);
+}
+
+Because {@code LaunchActivity} runs in isolation, you cannot use the +{@link android.test.TouchUtils} library to manipulate UI controls. To directly +click a {@link android.widget.Button}, you can call the +{@link android.view.View#performClick()} method instead.
+ + + + + + + diff --git a/docs/html/training/activity-testing/index.jd b/docs/html/training/activity-testing/index.jd new file mode 100644 index 000000000000..ddede712d83e --- /dev/null +++ b/docs/html/training/activity-testing/index.jd @@ -0,0 +1,68 @@ +page.title=Testing Your Android Activity +page.tags="testing" + +trainingnavtop=true +startpage=true + +@jd:body + +You should be writing and running tests as part of your Android application +development cycle. Well-written tests can help you to catch bugs early in +development and give you confidence in your code.
+ +A test case defines a set of objects and methods to run multiple +tests independently from each other. Test cases can be organized into +test suites and run programmatically, in a repeatable manner, with +a test runner provided by a testing framework.
+ +The lessons in this class teaches you how to use the Android's custom +testing framework that is based on the popular JUnit framework. You can +write test cases to verify specific behavior in your application, and check for +consistency across different Android devices. Your test cases also serve as a +form of internal code documentation by describing the expected behavior of +app components.
+ +AndroidTestingFun.zip
+Before you start writing and running your tests, you should set up your test +development environment. This lesson teaches you how to set up the Eclipse +IDE to build and run tests, and how to +build and run tests with the Gradle framework by using the command line +interface.
+ +Note: To help you get started, the lessons are +based on Eclipse with the ADT plugin. However, for your own test development, you +are free to use the IDE of your choice or the command-line.
+ +Eclipse with the Android Developer Tools (ADT) plugin provides an integrated +development environment for you to create, build, and run Android application +test cases from a graphical user interface (GUI). A convenient feature that +Eclipse provides is the ability to auto-generate a new test project that +corresponds with your Android application project. + +
To set up your test environment in Eclipse:
+ +You should now be able to create, build, and run test +cases from your Eclipse environment. To learn how to perform these tasks in +Eclipse, proceed to Creating and Running +a Test Case.
+ +If you are using Gradle version 1.6 or higher as your build environment, you +can build and run your Android application tests from the command line by using +the Gradle Wrapper. Make sure that in your {@code gradle.build} file, the +minSdkVersion +attribute in the {@code defaultConfig} section is set to 8 or higher. You can +refer to the sample {@code gradle.build} file that is +included in the download bundle for this training class.
+To run your tests with the Gradle Wrapper:
+./gradlew build connectedCheck+
To learn more about using Gradle for Android testing, see the +Gradle Plugin User Guide.
+To learn more about using command line tools other than Gradle for test +development, see +Testing from Other IDEs.
+ diff --git a/docs/html/training/testing.jd b/docs/html/training/testing.jd new file mode 100644 index 000000000000..c55370db0b0f --- /dev/null +++ b/docs/html/training/testing.jd @@ -0,0 +1,7 @@ +page.title=Best Practices for Testing +page.trainingcourse=true + +@jd:body + +These classes and articles provide information about how to +test your Android application.
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 40c170edd845..b884620916cf 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -1205,6 +1205,45 @@ include the action bar on devices running Android 2.1 or higher." +