我正在使用Google推荐的Android测试框架:ActivityInstrumentationTestCase2。我在 RANDOM 测试运行中遇到了以下错误,但持续死亡。这意味着有时所有测试都通过了(快乐!),但很多时候它随机地失败了这三个错误中的任何一个。这令人沮丧,让我对测试结果没有信心。
为了详细描述问题,我提供了我的测试类'简化伪代码和下面的三个问题。两个测试用例彼此独立。
public class FirstActivityTest
extends ActivityInstrumentationTestCase2<FirstActivity> {
private FirstActivity mActivity;
private ActivityMonitor mActivityMonitor;
public FirstActivityTest () {
super(FirstActivity.class);
}
public void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(false);
mActivity = getActivity();
assertNotNull("Cannot start test since target Activity is NULL!", mActivity);
mActivityMonitor = getInstrumentation().addMonitor(SecondActivity.class.getName(), null, false);
}
public void tearDown() throws Exception {
super.tearDown();
if(mActivity != null) {
mActivity.finish();
mActivity = null;
}
if(mActivityMonitor != null) {
getInstrumentation().removeMonitor(mActivityMonitor);
mActivityMonitor = null;
}
}
/**
* Open FirstActivity, enter a text and click submit button.
* Verifies SecondActivity is open.
*/
public void testA_HappyPath() {
Activity secondActivity = null;
try {
//(Omitted) Get edit text and enter a valid value
//(Omitted) Find submitButton view
//Click submit button
TouchUtils.clickView(this, submitButton);
//Wait for result and validate:
secondActivity = mActivityMonitor.waitForActivityWithTimeout(10000);
assertNotNull("Result SecondActivity should NOT be null!", secondActivity );
} finally {
//Clean up:
if(secondActivity != null) {
secondActivity .finish();
secondActivity = null;
}
}
}
/**
* Open FirstActivity, do NOT enter a text and click submit button.
* Verifies error message is returned.
*/
public void testB_SadPath() {
//(Omitted) Find submitButton view
//Click submit button
TouchUtils.clickView(this, submitButton);
//(Omitted) Validate error message is displayed
}
}
现在,我一遍又一遍地运行这两个测试用例(它们将按字母顺序运行),结果如下:
任何有用的反馈表示赞赏。谢谢!
到目前为止,我已经处理了这三个问题,在互联网上研究了很多建议并做了几次尝试和错误。然而,没有一个人能够立即解决特定的问题 - 通过结合我发现的解决了上述问题(1)和(2)的问题,但仍然有问题(3)未解决。下面详细介绍了我为完成这项工作所做的修复。
ISSUE(1)ActivityMonitor.waitForActivityWithTimeout()返回NULL
1.1。我现在知道我必须在getActivit()之前声明getInstrumentation()。addMonitor()。请看我如何更改setUp()方法,这以某种方式修复了问题。任何了解这为何要求的人请告诉我们,我们对此表示赞赏。
1.2。在模拟器上,此调用偶尔会返回NULL,导致测试失败。我了解到这是因为等待时间太短了。因此,增加等待时间有助于防止ActivityMonitor过早返回。
ISSUE(2)下一个testB_SadPath()会在setUp()&gt;期间挂起getActivity()无限期
2.1。如上所述,这发生在前一个测试(testA_HappyPath)失败时。我以为我的tearDown()清理了所有东西并准备好下一个测试。发生的事情是,testA正在等待SecondActivity出现在屏幕上,但由于ActivityMonitor.waitForActivityWithTimeout()返回NULL,testA失败。 tearDown()执行得很好。问题是SecondActivity确实出现在屏幕上,但它永远不会在finally块中关闭,因为它的方法实例'secondActivity'仍为null。让SecondActivity活着并且在屏幕上徘徊导致下一个getActivity()挂起。我通过更改finally块来修复此问题,以确保SecondActivity是否存在,它会被关闭。
以下代码总结了这些变化(参见setUp(),最后是阻止)。
public class FirstActivityTest
extends ActivityInstrumentationTestCase2<FirstActivity> {
private FirstActivity mActivity;
private ActivityMonitor mActivityMonitor;
public FirstActivityTest () {
super(FirstActivity.class);
}
public void setUp() throws Exception {
super.setUp();
setActivityInitialTouchMode(false);
}
public void tearDown() throws Exception {
super.tearDown();
if(mActivity != null) {
mActivity.finish();
mActivity = null;
}
if(mActivityMonitor != null) {
getInstrumentation().removeMonitor(mActivityMonitor);
mActivityMonitor = null;
}
}
/**
* Open FirstActivity, enter a text and click submit button.
* Verifies SecondActivity is open.
*/
public void testA_HappyPath() {
mActivityMonitor = getInstrumentation().addMonitor(SecondActivity.class.getName(), null, false);
mActivity = getActivity();
assertNotNull("Cannot start test since target Activity is NULL!", mActivity);
Activity secondActivity = null;
try {
//(Omitted) Get edit text and enter a valid value
//(Omitted) Find submitButton view
//Click submit button
TouchUtils.clickView(this, submitButton);
//Wait for result and validate:
secondActivity = mActivityMonitor.waitForActivityWithTimeout(20000);
assertNotNull("Result SecondActivity should NOT be null!", secondActivity );
} finally {
//Clean up:
if(secondActivity == null) {
//If empty, wait longer because need to shut down the foreground activity, if any:
secondActivity = mActivityMonitor.waitForActivityWithTimeout(20000);
}
if(secondActivity != null) {
secondActivity .finish();
secondActivity = null;
}
}
}
/**
* Open FirstActivity, do NOT enter a text and click submit button.
* Verifies error message is returned.
*/
public void testB_SadPath() {
mActivity = getActivity();
assertNotNull("Cannot start test since target Activity is NULL!", mActivity);
//(Omitted) Find submitButton view
//Click submit button
TouchUtils.clickView(this, submitButton);
//(Omitted) Validate error message is displayed
}
}
ISSUE(3)testB_SadPath()经常在TouchUtils.clickView()上失败,并出现以下错误:“注入另一个应用程序需要INJECT_EVENTS权限”
我仍无法解决最后一期: - (
答案 0 :(得分:1)
ISSUE(3)testB_SadPath()经常在TouchUtils.clickView()上失败,并出现以下错误:“注入另一个应用程序需要INJECT_EVENTS权限”
我在Android单元测试中找到了另一种避免此问题的方法。我没有使用TouchUtils.clickView(),而是通过调用performClick()直接对按钮本身执行单击操作。以下修改过的测试代码解决了我偶尔的INJECT_EVENTS权限错误。特别是,请参阅populateDataAndClickSubmit()。
/**
* Open FirstActivity, enter a text and click submit button.
* Verifies SecondActivity is open.
*/
public void testA_HappyPath() {
mActivityMonitor = getInstrumentation().addMonitor(SecondActivity.class.getName(), null, false);
mActivity = getActivity();
assertNotNull("Cannot start test since target Activity is NULL!", mActivity);
Activity secondActivity = null;
try {
String dataValue = "MyNameIsNoLongerFooNorBar";
populateDataAndClickSubmit(dataValue);
//Wait for result and validate:
secondActivity = mActivityMonitor.waitForActivityWithTimeout(20000);
assertNotNull("Result SecondActivity should NOT be null!", secondActivity );
} finally {
//Clean up:
if(secondActivity == null) {
//If empty, wait longer because need to shut down the foreground activity, if any:
secondActivity = mActivityMonitor.waitForActivityWithTimeout(20000);
}
if(secondActivity != null) {
secondActivity.finish();
secondActivity = null;
}
}
}
/**
* Open FirstActivity, do NOT enter a text and click submit button.
* Verifies error message is returned.
*/
public void testB_SadPath() {
mActivity = getActivity();
assertNotNull("Cannot start test since target Activity is NULL!", mActivity);
String dataValue = null;
populateDataAndClickSubmit(dataValue);
//(Omitted) Validate error message is displayed
}
private void populateDataAndClickSubmit(final String dataValueString) {
final EditText editDataView = //(omitted) find it from the activity layout
final Button submitButton = //(Omitted) Find submitButton view
mActivity.runOnUiThread(
new Runnable() {
public void run() {
editDataView.setText(dataValueString);
submitButton.performClick();
}
}
);
//Wait and allow app to be idle while performClick to finish and activity re-drawn:
getInstrumentation().waitForIdleSync();
}
备注:强>