I am attempting to test simple UI with the following test case, The main idea is to set in the test some of the UI text (to mimic user input) and then actively click an event.
public class StackTestCase
extends ActivityInstrumentationTestCase2<Stack>
{
private StackDemo mActivity;
private EditText eaten;
public StuckTestCase() {
super("com.crocodil.software.stack", Stack.class);
}
public StuckTestCase(Class<Stack> activityClass) {
super("com.crocodil.software.stack", activityClass);
}
protected void setUp() throws Exception {
super.setUp();
mActivity = this.getActivity();
mCount = (Button) mActivity.findViewById(com.crocodil.software.stack.R.id.action);
eaten = (EditText) mActivity.findViewById(com.crocodil.software.stack.R.id.eaten);
}
public void testPreconditions() {
assertNotNull(mStatus);
}
public void testSimpleDefaults(){
double status = Double.valueOf(mStatus.getText().toString());
eaten.setText(2);
mCount.performClick();
assertEquals((status-2),Double.valueOf(mStatus.getText().toString()));
}
}
the running result is the exception -
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2802)
at android.view.ViewRoot.playSoundEffect(ViewRoot.java:2581)
at android.view.View.playSoundEffect(View.java:8516)
at android.view.View.performClick(View.java:2407)
at com.crocodil.software.stack.test.StackTestCase.testSimpleDefaults(StackTestCase.java:46)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:204)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:194)
at android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:186)
at android.test.AndroidTestRunner开发者_运维百科.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
This happens on each access to the UI elements and i was unable to avoid it by using handles or async task ? any suggestions?
This is an old question, but I'm giving you an answer anyway, in case someone stumbles upon it.
You are not allowed to change states of UI widgets from anywhere but the main thread (UI thread). Your performClick must be done like this:
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mCount.performClick();
}
});
But that is not all, you will also need to sync your instrumentation test with the ui, by adding the following line:
getInstrumentation().waitForIdleSync();
The sync line is usually placed immediately after the runOnUiThread() code.
The issue is that you can only touch / change views from the UI thread. You can use a runnable as Rober outlined or an annotation.
You can run all methods inside a test on the UI thread using the @UiThreadTest
annotation:
Update:
This @interface was deprecated in API level 24.
Use UiThreadTest instead. New tests should be written using the Android Testing Support Library.
@UiThreadTest
public void testSimpleDefaults(){
double status = Double.valueOf(mStatus.getText().toString());
eaten.setText(2);
mCount.performClick();
assertEquals((status-2),Double.valueOf(mStatus.getText().toString()));
}
精彩评论