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