Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40765a4a authored by quddusc's avatar quddusc Committed by Android Git Automerger
Browse files

am 2ef3952d: cherrypick from jb-mr2-docs docs: Android training for Activity...

am 2ef3952d: cherrypick from jb-mr2-docs docs: Android training for Activity testing. Change-Id: I7167732c849d5a4a36c808cc852ddfcdc8e60bd7

* commit '2ef3952d':
  cherrypick from jb-mr2-docs docs: Android training for Activity testing. Change-Id: I7167732c849d5a4a36c808cc852ddfcdc8e60bd7
parents 8cb2f42e 2ef3952d
Loading
Loading
Loading
Loading
+464 KiB

File added.

No diff preview for this file type.

+12.6 KiB
Loading image diff...
+227 −0
Original line number Diff line number Diff line
page.title=Creating and Running a Test Case
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="#testcase">Create a Test Case for Activity Testing</a>
      <ol>
      <li><a href="#fixture">Set Up Your Test Fixture</a></li>
      <li><a href="#preconditions">Add Test Preconditions</a></li>
      <li><a href="#test_method">Add Test Methods to Verify Your Activity</a></li>
      </ol>
  </li>
  <li><a href="#build_run">Build and Run Your Test</a></li>
</ol>

<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}tools/testing/testing_android.html">Testing
Fundamentals</a></li>
</ul>

</div>
</div>
<p>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.</p>
<p class="note"><strong>Note:</strong> 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.</p>

<h2 id="testcase">Create a Test Case</h2>
<p>{@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.</p>
<p>By convention, your test package name should follow the same name as the
application package, suffixed with <strong>".tests"</strong>. 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 <strong>“Test”</strong>.</p>
<p>To create a new test case in Eclipse:</p>
<ol type="a">
   <li>In the Package Explorer, right-click on the {@code /src} directory for
your test project and select <strong>New &gt; Package</strong>.</li>
   <li>Set the <strong>Name</strong> field to
{@code &lt;your_app_package_name&gt;.tests} (for example,
{@code com.example.android.testingfun.tests}) and click
<strong>Finish</strong>.</li>
   <li>Right-click on the test package you created, and select
<strong>New &gt; Class</strong>.</li>
    <li>Set the <strong>Name</strong> field to
{@code &lt;your_app_activity_name&gt;Test} (for example,
{@code MyFirstTestActivityTest}) and click <strong>Finish</strong>.</li>
</ol>

<h3 id="fixture">Set Up Your Test Fixture</h3>
<p>A <em>test fixture</em> 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.
</p>
<p>To set up your test fixture in Eclipse:</p>
<ol>
<li>In the Package Explorer, double-click on the test case that you created
earlier to bring up the Eclipse Java editor, then modify your test case class
to extend one of the sub-classes of {@link android.test.ActivityTestCase}.
<p>For example:</p>
<pre>
public class MyFirstTestActivityTest
        extends ActivityInstrumentationTestCase2&lt;MyFirstTestActivity&gt; {
</pre>
</li>
<li>Next, add the constructor and {@link junit.framework.TestCase#setUp()}
methods to your test case, and add variable declarations for the
{@link android.app.Activity} that you want to test.</p>
<p>For example:</p>
<pre>
public class MyFirstTestActivityTest
        extends ActivityInstrumentationTestCase2&lt;MyFirstTestActivity&gt; {

    private MyFirstTestActivity mFirstTestActivity;
    private TextView mFirstTestText;

    public MyFirstTestActivityTest() {
        super(MyFirstTestActivity.class);
    }

    &#64;Override
    protected void setUp() throws Exception {
        super.setUp();
        mFirstTestActivity = getActivity();
        mFirstTestText =
                (TextView) mFirstTestActivity
                .findViewById(R.id.my_first_test_text_view);
    }
}
</pre>
<p>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.</p>
</li>
</ol>

<p>Typically, in the {@link junit.framework.TestCase#setUp()} method, you
should:</p>
<ul>
<li>Invoke the superclass constructor for
{@link junit.framework.TestCase#setUp()}, which is required by JUnit.</li>
<li>Initialize your test fixture state by:
   <ul>
   <li>Defining the instance variables that store the state of the fixture.</li>
   <li>Creating and storing a reference to an instance of the
{@link android.app.Activity} under test.</li>
   <li>Obtaining a reference to any UI components in the
{@link android.app.Activity} that you want to test.</li>
   </ul>
</ul>

<p>You can use the
{@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to
get a reference to the {@link android.app.Activity} under test.</p>

<h3 id="preconditions">Add Test Preconditions</h3>
<p>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()}.</p>

<p>For example, you might want to add a {@code testPreconditons()} method like
this to your test case:</p>

<pre>
public void testPreconditions() {
    assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity);
    assertNotNull(“mFirstTestText is null”, mFirstTestText);
}
</pre>

<p>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.
<ul>
<li>If the condition is false, the assertion method throws an
{@link android.test.AssertionFailedError} exception, which is then typically
reported by the test runner. You can provide a string in the first argument of
your assertion method to give some contextual details if the assertion fails.</li>
<li>If the condition is true, the test passes.</li>
</ul>
<p>In both cases, the test runner proceeds to run the other test methods in the
test case.</p>

<h3 id="test_method">Add Test Methods to Verify Your Activity</h3>
<p>Next, add one or more test methods to verify the layout and functional
behavior of your {@link android.app.Activity}.</p>
<p>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:</p>
<pre>
public void testMyFirstTestTextView_labelText() {
    final String expected =
            mFirstTestActivity.getString(R.string.my_first_test);
    final String actual = mFirstTestText.getText().toString();
    assertEquals(expected, actual);
}
</pre>

<p>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.</p>
<p class="note"><strong>Note:</strong> 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.</p>
<p>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.</p>
<p>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.</p>
<p>If you added a {@code testPreconditions()} method, put your test methods
after the {@code testPreconditions()} definition in your Java class.</p>
<p>For a complete test case example, take a look at
{@code MyFirstTestActivityTest.java} in the sample app.</p>

<h2 id="build_run">Build and Run Your Test</h2>
<p>You can build and run your test easily from the Package Explorer in
Eclipse.</p>
<p>To build and run your test:</p>
<ol>
<li>Connect an Android device to your machine. On the device or emulator, open
the <strong>Settings</strong> menu, select <strong>Developer options</strong>
and make sure that USB debugging is enabled.</li>
<li>In the Project Explorer, right-click on the test class that you created
earlier and select <strong>Run As &gt; Android Junit Test</strong>.</li>
<li>In the Android Device Chooser dialog, select the device that you just
connected, then click <strong>OK</strong>.</li>
<li>In the JUnit view, verify that the test passes with no errors or failures.</li>
</ol>
<p>For example, if the test case passes with no errors, the result should look
like this:</p>
<img src="{@docRoot}images/training/activity-testing_lesson2_MyFirstTestActivityTest_result.png" alt="" />
<p class="img-caption">
  <strong>Figure 1.</strong> Result of a test with no errors.
</p>


+166 −0
Original line number Diff line number Diff line
page.title=Creating Functional Tests
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="#test_methods">Add Test Method to Validate Functional Behavior</a>
   <ol>
      <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li>
      <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li>
   </ol>
   </li>
</ol>

<h2>Try it out</h2>
<div class="download-box">
 <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip"
class="button">Download the demo</a>
 <p class="filename">AndroidTestingFun.zip</p>
</div>

</div>
</div>
<p>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.</p>

<p>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.</p>

<p>For a complete test case example, take a look at
{@code SenderActivityTest.java} in the sample app.</p>

<h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2>
<p id="test_goals">Your functional testing goals might include:</p>
<ul>
<li>Verifying that a target {@link android.app.Activity} is started when a
UI control is pushed in the sender {@link android.app.Activity}.</li>
<li>Verifying that the target {@link android.app.Activity} displays the
correct data based on the user's input in the sender
{@link android.app.Activity}.</li>
</ul>
<p>You might implement your test method like this:</p>

<pre>
&#64;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
    ...
}
</pre>
<p>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.</p>

<h2 id="activitymonitor">Set up an ActivityMonitor</h2>
<p>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.</p>
<p>Generally, to use an
{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p>
<ol>
<li>Retrieve the {@link android.app.Instrumentation} instance for your test
case by using the
{@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li>
<li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to
the current instrumentation using one of the {@link android.app.Instrumentation}
{@code addMonitor()} methods. The match criteria can be specified as an
{@link android.content.IntentFilter} or a class name string.</li>
<li>Wait for the {@link android.app.Activity} to start.</li>
<li>Verify that the monitor hits were incremented.</li>
<li>Remove the monitor.</li>
</ol>
<p>For example:</p>
<pre>
// 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);
</pre>

<h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2>
<p>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.</p>
<p>Generally, to send a string input value to an {@link android.widget.EditText}
object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p>
<ol>
<li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()}
method to run the {@link android.view.View#requestFocus()} call synchronously
in a loop. This way, the UI thread is blocked until focus is received.</li>
<li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait
for the main thread to become idle (that is, have no more events to process).</li>
<li>Send a text string to the {@link android.widget.EditText} by calling
{@link android.app.Instrumentation#sendStringSync(java.lang.String)
sendStringSync()} and pass your input string as the parameter.</p>
</ol>
<p>For example:</p>
<pre>
// Send string input value
getInstrumentation().runOnMainSync(new Runnable() {
    &#64;Override
    public void run() {
        senderMessageEditText.requestFocus();
    }
});
getInstrumentation().waitForIdleSync();
getInstrumentation().sendStringSync("Hello Android!");
getInstrumentation().waitForIdleSync();
</pre>







+216 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading