1 page.title=Creating Functional Tests 2 trainingnavtop=true 3 @jd:body 4 5 <!-- This is the training bar --> 6 <div id="tb-wrapper"> 7 <div id="tb"> 8 9 <h2>This lesson teaches you to</h2> 10 <ol> 11 <li><a href="#test_methods">Add Test Method to Validate Functional Behavior</a> 12 <ol> 13 <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li> 14 <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li> 15 </ol> 16 </li> 17 </ol> 18 19 <h2>Try it out</h2> 20 <div class="download-box"> 21 <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" 22 class="button">Download the demo</a> 23 <p class="filename">AndroidTestingFun.zip</p> 24 </div> 25 26 </div> 27 </div> 28 <p>Functional testing involves verifying that individual application 29 components work together as expected by the user. For example, you can create a 30 functional test to verify that an {@link android.app.Activity} correctly 31 launches a target {@link android.app.Activity} when the user performs a UI 32 interaction.</p> 33 34 <p>To create a functional test for your {@link android.app.Activity}, your test 35 class should extend {@link android.test.ActivityInstrumentationTestCase2}. 36 Unlike {@link android.test.ActivityUnitTestCase}, 37 tests in {@link android.test.ActivityInstrumentationTestCase2} can 38 communicate with the Android system and send keyboard input and click events to 39 the UI.</p> 40 41 <p>For a complete test case example, take a look at 42 {@code SenderActivityTest.java} in the sample app.</p> 43 44 <h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2> 45 <p id="test_goals">Your functional testing goals might include:</p> 46 <ul> 47 <li>Verifying that a target {@link android.app.Activity} is started when a 48 UI control is pushed in the sender {@link android.app.Activity}.</li> 49 <li>Verifying that the target {@link android.app.Activity} displays the 50 correct data based on the user's input in the sender 51 {@link android.app.Activity}.</li> 52 </ul> 53 <p>You might implement your test method like this:</p> 54 55 <pre> 56 @MediumTest 57 public void testSendMessageToReceiverActivity() { 58 final Button sendToReceiverButton = (Button) 59 mSenderActivity.findViewById(R.id.send_message_button); 60 61 final EditText senderMessageEditText = (EditText) 62 mSenderActivity.findViewById(R.id.message_input_edit_text); 63 64 // Set up an ActivityMonitor 65 ... 66 67 // Send string input value 68 ... 69 70 // Validate that ReceiverActivity is started 71 ... 72 73 // Validate that ReceiverActivity has the correct data 74 ... 75 76 // Remove the ActivityMonitor 77 ... 78 } 79 </pre> 80 <p>The test waits for an {@link android.app.Activity} that matches this monitor, 81 otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was 82 started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} 83 that you set 84 up earlier receives a hit. You can use the assertion methods to verify that 85 the {@code ReceiverActivity} is indeed started, and that the hit count on the 86 {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented 87 as expected.</p> 88 89 <h2 id="activitymonitor">Set up an ActivityMonitor</h2> 90 <p>To monitor a single {@link android.app.Activity} in your application, you 91 can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}. 92 The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is 93 notified by the system whenever an {@link android.app.Activity} that matches your criteria is started. 94 If a match is found, the monitors hit count is updated.</p> 95 <p>Generally, to use an 96 {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p> 97 <ol> 98 <li>Retrieve the {@link android.app.Instrumentation} instance for your test 99 case by using the 100 {@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li> 101 <li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to 102 the current instrumentation using one of the {@link android.app.Instrumentation} 103 {@code addMonitor()} methods. The match criteria can be specified as an 104 {@link android.content.IntentFilter} or a class name string.</li> 105 <li>Wait for the {@link android.app.Activity} to start.</li> 106 <li>Verify that the monitor hits were incremented.</li> 107 <li>Remove the monitor.</li> 108 </ol> 109 <p>For example:</p> 110 <pre> 111 // Set up an ActivityMonitor 112 ActivityMonitor receiverActivityMonitor = 113 getInstrumentation().addMonitor(ReceiverActivity.class.getName(), 114 null, false); 115 116 // Validate that ReceiverActivity is started 117 TouchUtils.clickView(this, sendToReceiverButton); 118 ReceiverActivity receiverActivity = (ReceiverActivity) 119 receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS); 120 assertNotNull("ReceiverActivity is null", receiverActivity); 121 assertEquals("Monitor for ReceiverActivity has not been called", 122 1, receiverActivityMonitor.getHits()); 123 assertEquals("Activity is of wrong type", 124 ReceiverActivity.class, receiverActivity.getClass()); 125 126 // Remove the ActivityMonitor 127 getInstrumentation().removeMonitor(receiverActivityMonitor); 128 </pre> 129 130 <h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2> 131 <p>If your {@link android.app.Activity} has an {@link android.widget.EditText} 132 field, you might want to test that users can enter values into the 133 {@link android.widget.EditText} object.</p> 134 <p>Generally, to send a string input value to an {@link android.widget.EditText} 135 object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p> 136 <ol> 137 <li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()} 138 method to run the {@link android.view.View#requestFocus()} call synchronously 139 in a loop. This way, the UI thread is blocked until focus is received.</li> 140 <li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait 141 for the main thread to become idle (that is, have no more events to process).</li> 142 <li>Send a text string to the {@link android.widget.EditText} by calling 143 {@link android.app.Instrumentation#sendStringSync(java.lang.String) 144 sendStringSync()} and pass your input string as the parameter.</p> 145 </ol> 146 <p>For example:</p> 147 <pre> 148 // Send string input value 149 getInstrumentation().runOnMainSync(new Runnable() { 150 @Override 151 public void run() { 152 senderMessageEditText.requestFocus(); 153 } 154 }); 155 getInstrumentation().waitForIdleSync(); 156 getInstrumentation().sendStringSync("Hello Android!"); 157 getInstrumentation().waitForIdleSync(); 158 </pre> 159 160 161 162 163 164 165 166 167