1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.example.spinner.test; 18 19 import com.android.example.spinner.SpinnerActivity; 20 21 import android.app.Instrumentation; 22 import android.test.ActivityInstrumentationTestCase2; 23 import android.test.UiThreadTest; 24 import android.view.KeyEvent; 25 import android.widget.Spinner; 26 import android.widget.SpinnerAdapter; 27 import android.widget.TextView; 28 29 /* 30 * Tests the example application Spinner. Uses the instrumentation test class 31 * ActivityInstrumentationTestCase2 as its base class. The tests include 32 * - test initial conditions 33 * - test the UI 34 * - state management - preserving state after the app is shut down and restarted, preserving 35 * state after the app is hidden (paused) and re-displayed (resumed) 36 * 37 * Demonstrates the use of JUnit setUp() and assert() methods. 38 */ 39 public class SpinnerActivityTest extends ActivityInstrumentationTestCase2<SpinnerActivity> { 40 41 // Number of items in the spinner's backing mLocalAdapter 42 43 public static final int ADAPTER_COUNT = 9; 44 45 // The location of Saturn in the backing mLocalAdapter array (0-based) 46 47 public static final int TEST_POSITION = 5; 48 49 // Set the initial position of the spinner to zero 50 51 public static final int INITIAL_POSITION = 0; 52 53 // The initial position corresponds to Mercury 54 55 public static final String INITIAL_SELECTION = "Mercury"; 56 57 // Test values of position and selection for the testStateDestroy test 58 59 public static final int TEST_STATE_DESTROY_POSITION = 2; 60 public static final String TEST_STATE_DESTROY_SELECTION = "Earth"; 61 62 // Test values of position and selection for the testStatePause test 63 64 public static final int TEST_STATE_PAUSE_POSITION = 4; 65 public static final String TEST_STATE_PAUSE_SELECTION = "Jupiter"; 66 67 // The Application object for the application under test 68 69 private SpinnerActivity mActivity; 70 71 // String displayed in the spinner in the app under test 72 73 private String mSelection; 74 75 // The currently selected position in the spinner in the app under test 76 77 private int mPos; 78 79 /* 80 * The Spinner object in the app under test. Used with instrumentation to control the 81 * app under test. 82 */ 83 84 private Spinner mSpinner; 85 86 /* 87 * The data backing the Spinner in the app under test. 88 */ 89 90 private SpinnerAdapter mPlanetData; 91 92 /* 93 * Constructor for the test class. Required by Android test classes. The constructor 94 * must call the super constructor, providing the Android package name of the app under test 95 * and the Java class name of the activity in that application that handles the MAIN intent. 96 */ SpinnerActivityTest()97 public SpinnerActivityTest() { 98 99 super("com.android.example.spinner", SpinnerActivity.class); 100 } 101 102 /* 103 * Sets up the test environment before each test. 104 * @see android.test.ActivityInstrumentationTestCase2#setUp() 105 */ 106 @Override setUp()107 protected void setUp() throws Exception { 108 109 /* 110 * Call the super constructor (required by JUnit) 111 */ 112 113 super.setUp(); 114 115 /* 116 * prepare to send key events to the app under test by turning off touch mode. 117 * Must be done before the first call to getActivity() 118 */ 119 120 setActivityInitialTouchMode(false); 121 122 /* 123 * Start the app under test by starting its main activity. The test runner already knows 124 * which activity this is from the call to the super constructor, as mentioned 125 * previously. The tests can now use instrumentation to directly access the main 126 * activity through mActivity. 127 */ 128 mActivity = getActivity(); 129 130 /* 131 * Get references to objects in the application under test. These are 132 * tested to ensure that the app under test has initialized correctly. 133 */ 134 135 mSpinner = (Spinner)mActivity.findViewById(com.android.example.spinner.R.id.Spinner01); 136 137 mPlanetData = mSpinner.getAdapter(); 138 139 } 140 141 /* 142 * Tests the initial values of key objects in the app under test, to ensure the initial 143 * conditions make sense. If one of these is not initialized correctly, then subsequent 144 * tests are suspect and should be ignored. 145 */ 146 testPreconditions()147 public void testPreconditions() { 148 149 /* 150 * An example of an initialization test. Assert that the item select listener in 151 * the main Activity is not null (has been set to a valid callback) 152 */ 153 assertTrue(mSpinner.getOnItemSelectedListener() != null); 154 155 /* 156 * Test that the spinner's backing mLocalAdapter was initialized correctly. 157 */ 158 159 assertTrue(mPlanetData != null); 160 161 /* 162 * Also ensure that the backing mLocalAdapter has the correct number of entries. 163 */ 164 165 assertEquals(mPlanetData.getCount(), ADAPTER_COUNT); 166 } 167 168 /* 169 * Tests the UI of the main activity. Sends key events (keystrokes) to the UI, then checks 170 * if the resulting spinner state is consistent with the attempted selection. 171 */ testSpinnerUI()172 public void testSpinnerUI() { 173 174 /* 175 * Request focus for the spinner widget in the application under test, 176 * and set its initial position. This code interacts with the app's View 177 * so it has to run on the app's thread not the test's thread. 178 * 179 * To do this, pass the necessary code to the application with 180 * runOnUiThread(). The parameter is an anonymous Runnable object that 181 * contains the Java statements put in it by its run() method. 182 */ 183 mActivity.runOnUiThread( 184 new Runnable() { 185 public void run() { 186 mSpinner.requestFocus(); 187 mSpinner.setSelection(INITIAL_POSITION); 188 } 189 } 190 ); 191 192 // Activate the spinner by clicking the center keypad key 193 194 this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); 195 196 // send 5 down arrow keys to the spinner 197 198 for (int i = 1; i <= TEST_POSITION; i++) { 199 200 this.sendKeys(KeyEvent.KEYCODE_DPAD_DOWN); 201 } 202 203 // select the item at the current spinner position 204 205 this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); 206 207 // get the position of the selected item 208 209 mPos = mSpinner.getSelectedItemPosition(); 210 211 /* 212 * from the spinner's data mLocalAdapter, get the object at the selected position 213 * (this is a String value) 214 */ 215 216 mSelection = (String)mSpinner.getItemAtPosition(mPos); 217 218 /* 219 * Get the TextView widget that displays the result of selecting an item from the spinner 220 */ 221 222 TextView resultView = 223 (TextView) mActivity.findViewById(com.android.example.spinner.R.id.SpinnerResult); 224 225 // Get the String value in the EditText object 226 227 String resultText = (String) resultView.getText(); 228 229 /* 230 * Confirm that the EditText contains the same value as the data in the mLocalAdapter 231 */ 232 233 assertEquals(resultText,mSelection); 234 } 235 236 /* 237 * Tests that the activity under test maintains the spinner state when the activity halts 238 * and then restarts (for example, if the device reboots). Sets the spinner to a 239 * certain state, calls finish() on the activity, restarts the activity, and then 240 * checks that the spinner has the same state. 241 * 242 */ 243 testStateDestroy()244 public void testStateDestroy() { 245 246 /* 247 * Set the position and value of the spinner in the Activity. The test runner's 248 * instrumentation enables this by running the test app and the main app in the same 249 * process. 250 */ 251 252 253 mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION); 254 255 mActivity.setSpinnerSelection(TEST_STATE_DESTROY_SELECTION); 256 257 // Halt the Activity by calling Activity.finish() on it 258 259 mActivity.finish(); 260 261 // Restart the activity by calling ActivityInstrumentationTestCase2.getActivity() 262 263 mActivity = this.getActivity(); 264 265 /* 266 * Get the current position and selection from the activity. 267 */ 268 269 int currentPosition = mActivity.getSpinnerPosition(); 270 String currentSelection = mActivity.getSpinnerSelection(); 271 272 // test that they are the same. 273 274 assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition); 275 276 assertEquals(TEST_STATE_DESTROY_SELECTION, currentSelection); 277 } 278 279 /* 280 * Tests that the activity under test maintains the spinner's state when the activity is 281 * paused and then resumed. 282 * 283 * Calls the activity's onResume() method. Changes the spinner's state by 284 * altering the activity's View. This means the test must run 285 * on the UI Thread. All the statements in the test method may be run on 286 * that thread, so instead of using the runOnUiThread() method, the 287 * @UiThreadTest is used. 288 */ 289 @UiThreadTest 290 testStatePause()291 public void testStatePause() { 292 293 /* 294 * Get the instrumentation object for this application. This object 295 * does all the instrumentation work for the test runner 296 */ 297 298 Instrumentation instr = this.getInstrumentation(); 299 300 /* 301 * Set the activity's fields for the position and value of the spinner 302 */ 303 304 mActivity.setSpinnerPosition(TEST_STATE_PAUSE_POSITION); 305 306 mActivity.setSpinnerSelection(TEST_STATE_PAUSE_SELECTION); 307 308 /* 309 * Use the instrumentation to onPause() on the currently running Activity. 310 * This analogous to calling finish() in the testStateDestroy() method. 311 * This way demonstrates using the test class' instrumentation. 312 */ 313 314 instr.callActivityOnPause(mActivity); 315 316 /* 317 * Set the spinner to a test position 318 */ 319 320 mActivity.setSpinnerPosition(0); 321 322 mActivity.setSpinnerSelection(""); 323 324 /* 325 * Call the activity's onResume() method. This forces the activity 326 * to restore its state. 327 */ 328 329 instr.callActivityOnResume(mActivity); 330 331 /* 332 * Get the current state of the spinner 333 */ 334 335 int currentPosition = mActivity.getSpinnerPosition(); 336 337 String currentSelection = mActivity.getSpinnerSelection(); 338 339 assertEquals(TEST_STATE_PAUSE_POSITION,currentPosition); 340 assertEquals(TEST_STATE_PAUSE_SELECTION,currentSelection); 341 } 342 343 } 344