【发布时间】:2013-10-25 23:34:42
【问题描述】:
如题,谁能解释一下runOnUiThread()方法和@UiThreadTest注解的区别?我一直在阅读使用两者的 Android 测试教程 (http://developer.android.com/tools/testing/activity_test.html)。它指出:
测试应用程序中与被测应用程序的视图交互的代码必须在主应用程序的线程(也称为 UI 线程)中运行。为此,您使用 Activity.runOnUiThread() 方法
和:
@UiThreadTest 注释告诉 Android 构建此方法,以便它在 UI 线程上运行。这允许该方法在被测应用程序中更改微调器小部件的状态。
对于runOnUi()方法,有问题的代码是
public void testASpinnerUI()
{
mActivity.runOnUiThread(
new Runnable()
{
@Override
public void run()
{
mSpinner.requestFocus();
mSpinner.setSelection(INITIAL_POSITION);
}// end of run
} // end of runnable
); //end of runOnUiThread
this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
for (int i = 0; i < TEST_POSITION; i++)
{
this.sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
}
this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
mPos = mSpinner.getSelectedItemPosition();
mSelection = (String) mSpinner.getItemAtPosition(mPos);
TextView resultView = (TextView) mActivity.findViewById(com.android.example.spinner.R.id.SpinnerResult);
String resultText = (String) resultView.getText();
assertEquals(resultText, mSelection);
}
对于@UiThreadTest 注解:
@UiThreadTest
public void testStatePause()
{
Instrumentation mInstr = this.getInstrumentation();
mActivity.setSpinnerPosition(TEST_STATE_PAUSE_POSITION);
mActivity.setSpinnerSelection(TEST_STATE_PAUSE_SELECTION);
mInstr.callActivityOnPause(mActivity);
mActivity.setSpinnerPosition(0);
mActivity.setSpinnerSelection("");
mInstr.callActivityOnResume(mActivity);
int currentPosition = mActivity.getSpinnerPosition();
String currentSelection = mActivity.getSpinnerSelection();
assertEquals(TEST_STATE_PAUSE_POSITION, currentPosition);
assertEquals(TEST_STATE_PAUSE_SELECTION, currentSelection);
}
它们似乎是可互换的,因为我可以从带注释的测试中删除注释并将其内容包含在 runOnUiThread() 方法中并且它通过了。同样,我可以从另一个测试中删除 runOnUiThread() 方法并添加 @UiThreadTest 注释,它通过了。
那么有什么区别呢?
此外,本教程还包括另一个测试:
public void testStateDestroy()
{
mActivity.setSpinnerPosition(TEST_STATE_DESTROY_POSITION);
mActivity.setSpinnerSelection(TEST_STATE_DESTROY_SELECTION);
mActivity.finish();
mActivity = getActivity();
int currentPosition = mActivity.getSpinnerPosition();
String currentSelection = mActivity.getSpinnerSelection();
assertEquals(TEST_STATE_DESTROY_POSITION, currentPosition);
assertEquals(TEST_STATE_DESTROY_SELECTION, currentSelection);
}
此测试也与活动交互,但不需要@UiThreadTest 注释或runOnUiThread() 方法。这是为什么呢?
【问题讨论】:
-
第三个测试肯定看起来不是线程安全的。
-
它并没有失败。其他测试没有 runOnUi 方法或 @UiThreadTest 注释
-
对不起,重新阅读测试后,不,这不是比赛。设置和读取都发生在测试线程中(假设 UI 线程没有触及这些值)。因此,
set/get对不是竞争条件。finish()调用可能是,因为我们没有等待它,但这会使测试无效,而不是失败(即,它没有测试正确的东西,尽管结果可能仍然是success)。 -
当我使用
@UiThreadTest而不是@Test时,Android Studio 会将测试名称设为灰色,就好像没有人调用它一样。这些天必须添加@Test!
标签: android unit-testing junit