ActivityInstrumentationTestCase2和Robotium测试用例一直挂起,直到在模拟器上按下/ home,为什么?

时间:2013-11-21 05:22:31

标签: android unit-testing robotium

我正在开发一个带有单个活动的图形计算器应用程序。 (Android API 10) 布局相当复杂,40多个按钮占据了屏幕的下半部分 和一个框架布局作为屏幕的顶部。框架布局是一个子类 " ScreenFrame"它拥有"屏幕"的计算器。每个视图/视图组 在ScreenFrame中显示的是一个显示计算的自定义视图/视图组 用户正在表演。想想TI图形计算器,可以看到整个表达式 带有操作符号......

我一直在编写JUnit测试,主要是子类化AndroidTestCase,因为我只需要 用于测试大部分代码的上下文,而不是整个活动框架。 但是,我想要开始编写功能测试用例 应用程序的某些部分需要整个活动框架才能运行。

所以这就是让我彻底难倒的问题。 首先,我将展示测试用例的代码

public class CommandTest extends ActivityInstrumentationTestCase2<Calculator> {

    private Calculator _calculator;

    public CommandTest(){
        super(Calculator.class);
    }

    @Override
    protected void setUp() throws Exception {
        setActivityInitialTouchMode(true);
        _calculator = getActivity();
        super.setUp();
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
        _calculator.finish(); // doesn't make a difference if this line is there or not
    }

    public void testCircleBadSyntax1() {
        _calculator.runOnUiThread(new Runnable() {
            @Override public void run() {
                Button twoButton = (Button) _calculator.findViewById(R.id.twoButton);
                twoButton.performClick();
                Button addButton = (Button) _calculator.findViewById(R.id.addButton);
                addButton.performClick();
                Button nineButton = (Button) _calculator.findViewById(R.id.nineButton);
                nineButton.performClick();
                Button enterButton = (Button) _calculator.findViewById(R.id.equalsButton);
                enterButton.performClick();
             }
        });
        Instrumentation inst = getInstrumentation();
        inst.waitForIdleSync();

        _calculator.runOnUiThread(new Runnable() {
             @Override public void run() {
                 ScreenFrame screenFrame = (ScreenFrame) _calculator.findViewById(R.id.screenFrame);
                 assertNotNull(screenFrame);
                 AnswerSymbolGroup answer = screenFrame.getLastAnswer();
                 INumber number = answer.getNumberAnswer();
                 assertEquals(number.getValueInt(), 11); 
            }
    });
        _calculator.finish();
    }
}

我刚刚向您展示了我如何设置所有内容以及上面的单个示例测试用例。所有测试用例都是相似的,测试的内容不是问题...主要的问题是,当我通过eclipse运行测试时,测试只是无限期地挂在第一个测试用例实例上,(我试着把它留给了只是为了看,它只是坐在那里,在第一个案例上有一个蓝色箭头超过45分钟)。非常奇怪的是,当我按下HOME按钮或模拟器上的后退按钮时,测试用例就会运行。它给出了适当的回应。您没有看到任何屏幕更改或按下按钮时应该看到的其他内容,但测试用例应该按原样运行。意味着它通过,或失败取决于我正在测试的代码。然后测试运行器在下一次测试时挂起,直到我再次按下后面或主页按钮。

这不是一个可行的解决方案。我想在一个测试文件中有十到二十个案例(有时甚至更多),我想让它们全部成功运行而不必在模拟器上按任何东西,特别是因为我有一个Jenkins CI设置我用于我没有问题的所有其他测试。

所以我认为像robotium这样的类型的测试框架更适合处理这些类型的测试。

我遇到了与机器人相同的问题。当我在模拟器显示的主屏幕上运行机器人测试用例时,测试用例启动,调出计算器屏幕,然后无限期挂起。当我按下后退按钮,然后重新打开应用程序时,测试用例从头开始并继续按预期工作,这意味着如果它正在测试的代码是正确的,它会通过,否则就会失败。但是,您可以使用robotium案例查看相应的更改。例如,如果给定的测试被调整为使用solo变量来单击按钮而没有runOnUiThreads的东西,按下两个按钮后屏幕上会出现两个,然后输入后的加号,九个和十一个被压了。在接下来的测试案例中,同样的事情发生了,它无可奈何地挂起。当我单击后退或回家时,然后重新打开应用程序,测试将继续。每个测试用例我都要重复这个过程。我没有尝试在我的jenkins单元中运行这些测试,(仍在研究如何运行无头机器人测试)。

我已经被困了好几天了,并且不觉得我应该再浪费时间去弄明白了。是否有其他人经历过这种行为。

我通常讨厌使用调试器来查找错误,因为我发现编写测试并将适当的输出记录到LOGCAT要花费更多时间。但是,我尝试在这种情况下运行调试器,以找出问题所在。 我知道测试用例挂在getActivity()行上......我在调试器中找到了我在主循环器中循环的点。 onCreate(),onStart()和onResume() 方法已经完成,整个屏幕都可见,但一旦发生这种情况 它会挂起,直到我按下后退按钮或主页按钮。

我真的想弄清楚为什么会发生这种情况,并且可以连续运行多个测试用例。

/ **在第一个两个答案来之后添加** / 对于第一个答案,我已经尝试将activity.finish()放在tearDown()方法中,它没有任何区别......

对于第二个答案,我已经尝试了在测试setUp和tearDown()中放置super.setUp()和super.tearDown()的所有可能的枚举,而不包括它们作为选项之一。< / p>

我尝试更彻底地运行调试器getActivity()方法,并且可以说代码在startActivitySync(Intent intent)方法中卡在Instrumentation类中。

在第391行getTargetContext()。startActivity(intent)运行,然后它位于同步锁的下一部分......

getTargetContext().startActivity(intent);

do{
    try{
        mSync.wait();
    } catch(InterruptedException e){
    }
}while(mWaitingActivities.contains(aw));

return aw.activity;

3 个答案:

答案 0 :(得分:1)

在tearDown方法中,您需要调用_calculator.finish();

对于打开多个活动的测试,robotium有一个方便的方法来完成所有这些活动:solo.finishOpenedActivities();

答案 1 :(得分:0)

我不确定它是否会对您有所帮助,但您应该在setUp方法的开头调用super.setUp();,并在tearDown方法结束时调用super.tearDown();。您也可以尝试删除它们。

顺便说一句,调用setActivityInitialTouchMode(false);没有意义,因为:

  

如果您不打电话,触摸模式将为false。如果你打电话   在您的活动开始后,它将无效。

答案 2 :(得分:0)

我有类似的问题。我可以通过将setAdapter()方法放在AsyncTask类中来解决我的问题。