如何在多个活动中测试Android应用程序?

时间:2009-11-18 22:30:24

标签: android automated-tests integration-testing android-testing

我们正在构建一个复杂的Android应用程序,其中包含许多活动中分布的许多屏幕和工作流程。我们的工作流程类似于您在银行的ATM机上看到的工作流程,例如,有一个Activity登录,转换到主菜单Activity,可以转换到基于用户的其他活动选择。

由于我们有如此多的工作流程,我们需要创建跨多个活动的自动化测试,以便我们可以从头到尾测试工作流程。例如,使用ATM示例,我们要输入有效的PIN,验证是否将我们发送到主菜单,选择提取现金,验证我们是否在提取现金屏幕等等,最终找到自己回到主菜单或“登出”。

我们已经玩过Android附带的测试API(例如ActivityInstrumentationTestCase2)和Positron,但似乎都无法超出单个Activity的范围进行测试,虽然我们可以在这些工具中找到一些用于某些单元测试的实用程序,但它们无法满足我们测试跨多个活动的测试场景的需求。

我们对xUnit框架,脚本,GUI录制器/播放等持开放态度,并欢迎任何建议。

14 个答案:

答案 0 :(得分:64)

我对回答我自己的赏金问题感到有些尴尬,但这里是......

我对此进行了高调和低调,并且无法相信在任何地方都没有发布任何答案。我已经非常接近了。我现在肯定可以运行跨越活动的测试,但我的实现似乎有一些时间问题,其中测试并不总是可靠地通过。这是我所知道的成功跨多个活动的唯一示例。希望我的提取和匿名化不会引入错误。这是一个简单的测试,我在登录活动中键入用户名和密码,然后在不同的“欢迎”活动中显示正确的欢迎消息:

package com.mycompany;

import android.app.*;
import android.content.*;
import android.test.*;
import android.test.suitebuilder.annotation.*;
import android.util.*;
import android.view.*;
import android.widget.*;

import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
import static com.mycompany.R.id.*;

public class LoginTests extends InstrumentationTestCase {

   @MediumTest
   public void testAValidUserCanLogIn() {

      Instrumentation instrumentation = getInstrumentation();

      // Register we are interested in the authentication activiry...
      Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(AuthenticateActivity.class.getName(), null, false);

      // Start the authentication activity as the first activity...
      Intent intent = new Intent(Intent.ACTION_MAIN);
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      intent.setClassName(instrumentation.getTargetContext(), AuthenticateActivity.class.getName());
      instrumentation.startActivitySync(intent);

      // Wait for it to start...
      Activity currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Type into the username field...
      View currentView = currentActivity.findViewById(username_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyUsername");

      // Type into the password field...
      currentView = currentActivity.findViewById(password_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyPassword");

      // Register we are interested in the welcome activity...
      // this has to be done before we do something that will send us to that
      // activity...
      instrumentation.removeMonitor(monitor);
      monitor = instrumentation.addMonitor(WelcomeActivity.class.getName(), null, false);

      // Click the login button...
      currentView = currentActivity.findViewById(login_button;
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(Button.class));
      TouchUtils.clickView(this, currentView);

      // Wait for the welcome page to start...
      currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Make sure we are logged in...
      currentView = currentActivity.findViewById(welcome_message);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(TextView.class));
      assertThat(((TextView)currentView).getText().toString(), is("Welcome, MyUsername!"));
   }
}

这段代码显然不是很易读。我实际上把它提取到一个带有类似英语的API的简单库中,所以我可以这样说:

type("myUsername").intoThe(username_field);
click(login_button);

我已经测试了大约4个活动的深度,并且我很满意这种方法虽然如我所说,但似乎偶尔出现时间问题,我还没有完全弄明白。我仍然有兴趣听取其他各种活动的测试方法。

答案 1 :(得分:21)

看看 Robotium
'一个开源测试框架,旨在使Android应用程序的自动黑盒测试比开箱即用的Android测试测试更快更容易。

主页: http://www.robotium.org/
资源: http://github.com/jayway/robotium

请注意,Robotium项目由我工作的公司维护

答案 2 :(得分:8)

你总是可以使用Robotium。它支持黑盒测试,就像Selenium一样,但支持Android。您可以在Robotium.org找到它

答案 3 :(得分:4)

我很惊讶没有人提到一些领先的自动功能测试工具。与Robotium相比,这些不需要编写Java代码。

MonkeyTalk :由Gorilla Logic公司支持的开源工具。优点:为非技术用户提供更容易录制和更高级别的脚本语言,并且是跨平台的(包括iOS)。鉴于这些优势作为要求,我们发现这是最佳解决方案。它还允许customization超出使用Javascript在其脚本语言中可以完成的任务。

Calabash-Android:一个用于Cucumber风格功能的开源工具。优点:使用Gherkin语言编写功能,即Business Readable,Domain Specific Language,可让您描述软件的行为,而无需详细说明该行为的实现方式。 cucumber-ios中的iOS提供了类似但不完全支持的功能。录制功能不如它们产生二进制输出那么好。

其他几个参考文献:

  • 以下是Robotium之间的一些additional comparisons, Monkeytalk和Calabash。它提到TestDroid是另一个 可能性。
  • 这个blog提到了上面加上NativeDriver和Bot-bot。

答案 4 :(得分:3)

我为Android创建了一个记录和播放工具,并在GitHub上提供了该工具。它易于配置和使用,无需编程,可以针对真实设备(无需植根)运行,并在播放测试时自动保存屏幕截图。

答案 5 :(得分:3)

首先,使用'ActivityInstrumentationTestCase2'而不是'InstrumentationTestCase'作为基类。我使用Robotium并定期测试多个活动。我发现我必须将登录活动指定为泛型类型(以及构造函数的类参数)。

'ActivityInstrumentationTestCase2'构造函数忽略package参数,不需要它。不推荐使用该包的构造函数。

来自Javadocs: “ActivityInstrumentationTestCase2(String pkg,Class activityClass) 不推荐使用此构造函数。使用ActivityInstrumentationTestCase2(Class)代替“

使用推荐的基类允许框架处理某些样板,例如启动您的活动。这是通过调用'getActivity()'来完成的,如果有必要的话。

答案 6 :(得分:3)

通过一些修改发现这个很有用。 首先getInstrumentation().waitForIdleSync()将解决SingleShot所说的脆弱性 此外,InstrumentationTestCase还有一个lauchActivity函数,可以替换起始活动行。

答案 7 :(得分:2)

你可以这样做,以避免片状等待时间不同步:

final Button btnLogin = (Button) getActivity().findViewById(R.id.button);
Instrumentation instrumentation = getInstrumentation();

// Register we are interested in the authentication activity...
Instrumentation.ActivityMonitor aMonitor = 
        instrumentation.addMonitor(mynextActivity.class.getName(), null, false);

getInstrumentation().runOnMainSync(new Runnable() {
         public void run() {
             btnLogin.performClick();
         }
     });

getInstrumentation().waitForIdleSync();

//check if we got at least one hit on the new activity
assertTrue(getInstrumentation().checkMonitorHit(aMonitor, 1)); 

答案 8 :(得分:1)

我正在做同样的事情,我可能会对这个问题的接受答案做出改变,但我确实遇到了 Calculuon ({{在搜索解决方案期间,我会发现<} em

答案 9 :(得分:0)

我没有亲自使用它,但ApplicationTestCase看起来可能就是你想要的。

答案 10 :(得分:0)

还有另一种方法可以使用ActivityInstrumentation类进行多项活动。 这是一个正常的自动化场景 首先得到你想要的对象的焦点,然后发送一个密钥 就那么简单 示例代码

button.requestFocus();
sendKeys(KeyEvent.KEYCODE_ENTER);

唯一的理解是每个API调用都会对我们有所帮助。

答案 11 :(得分:0)

接受的方法是否适用于不同应用程序的不同活动,由不同的证书签名?如果没有,Robotium是测试同一应用程序内活动的最佳方式。

答案 12 :(得分:0)

这个答案是基于已接受的答案,但经过修改以解决时间问题,在添加了大约六个测试后,这个问题对我来说变得一致。 @ pajato1获得了解决时间问题的功劳,如接受的答案评论所述。

/**
 * Creates a test Activity for a given fully qualified test class name.
 *
 * @param fullyQualifiedClassName The fully qualified name of test activity class.
 *
 * @return The test activity object or null if it could not be located.
 */
protected AbstractTestActivity getTestActivity(final String fullyQualifiedClassName) {
    AbstractTestActivity result = null;

    // Register our interest in the given activity and start it.
    Log.d(TAG, String.format("Running test (%s) with main class: %s.", getName(), fullyQualifiedClassName));
    instrumentation = getInstrumentation();

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClassName(instrumentation.getTargetContext(), fullyQualifiedClassName);
    // Wait for the activity to finish starting
    Activity activity = instrumentation.startActivitySync(intent);

    // Perform basic sanity checks.
    assertTrue("The activity is null!  Aborting.", activity != null);
    String format = "The test activity is of the wrong type (%s).";
    assertTrue(String.format(format, activity.getClass().getName()), activity.getClass().getName().equals(fullyQualifiedClassName));
    result = (AbstractTestActivity) activity;

    return result;
}

答案 13 :(得分:-2)

尝试使用Monkey工具测试

第1步:

打开android studio终端(工具 - >打开终端)

第2步:

要使用monkey,请打开命令提示符,然后只需导航到以下目录。

 export PATH=$PATH:/home/adt-bundle-linux-x86-20140702/sdk/platform-tools

第3步:

将此Monkey命令添加到终端并按Enter ..

在模拟器中看到魔力。

adb shell monkey -p com.example.yourpackage -v 500

500-它是频率计数或要发送以进行测试的事件数。

您可以更改此计数..

更多参考,

http://www.tutorialspoint.com/android/android_testing.htm

http://androidtesting.blogspot.in/2012/04/android-testing-with-monkey-tool.html