78

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

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

我们玩弄附带的Android测试的API(如ActivityInstrumentationTestCase2),并与Positron,但也似乎能够超越单一Activity的边界测试,同时我们可以发现这些工具中的一些工具一些单元测试,它们不能满足我们对跨多个活动的测试场景的需求。

我们对xUnit框架,脚本,GUI录像机/回放等开放,并会感谢任何建议。

+2

作为安卓4.1的,现在有来自Android的一个新的测试框架,支持测试跨活动,甚至整个系统:http://developer.android.com/tools/testing/testing_ui。html –

+1

[Robotium](https://code.google.com/p/robotium/)也适合这种需求,并且只需几行。 – Dori

回答

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活动的深度和很满意的办法,虽然工作正如我所说,似乎有一个偶然的时机问题,我还没有完全想到。我仍然有兴趣听到其他各种活动的测试方法。

+3

您可能会尝试添加FlakyTest注释,以便在计时问题导致其失败时自动重复测试。真的不是一个解决方案,而是在某些情况下可行的解决方法。 –

+0

感谢您写这篇文章!我正在寻找ActivityMonitors的功能来进行测试。我找不到它们。 –

+0

据我所知,上面所做的任何事情都无法使用'ActivityInstrumentationTestCase2' – ericn

0

我没有亲自使用它,但ApplicationTestCase看起来像它可能是你在找什么。

+0

不幸的是,没有例子表明情况如此。 – SingleShot

+0

是啊,看起来你是对的......被名字欺骗了。我无法弄清楚这一点。我目前使用的最佳方法是使用positron的ActivityUnitTestCase来验证下一个活动是否已启动,但这无助于构建连贯的故事。 或者,InstrumentationTestCase.launchActivity可能允许您启动任意数量的活动,但我仍然试图找出Instrumentation的东西。 – Eric

0

还有另一种方式来做到使用ActivityInstrumentation类的多个活动.. 其正常的自动化方案...... 首先得到你想要反对什么都聚焦然后发送键 这么简单 示例代码

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

唯一的事情就是理解每个API调用都会帮助我们。

8

您可以随时使用Robotium。它支持像Selenium一样的黑盒测试,但支持Android。你会在Robotium上找到它。ORG

+1

我上次查看Robotium无法用于各种活动。现在已经修好了吗? http://stackoverflow.com/questions/3840034/how-do-i-write-a-solo-robotium-testcase-that-uses-the-builtin-camera-to-take-a-pi – user77115

+3

它始终只要它们属于同一个过程,就跨越活动进行工作。 – Renas

21

看看Robotium
“创建,使Android应用程序自动黑盒测试一个开源测试框架显著更快,比什么是可能与Android的仪器测试出的最容易-框。'

首页: http://www.robotium.org/
来源: http://github.com/jayway/robotium

请注意Robotium项目是由我公司为

+0

嗨,这是否有一个记录器工具?我查了很多网站,发现了记录脚本并运行它的testdroid。不幸的是,它不是一个免费软件,你知道有什么免费软件可以做记录吗? – thndrkiss

+0

@thndrkiss:我不知道任何这样的工具。如果您在Robotium论坛上提出问题,您可能会得到更好的答案。 –

+2

Robotium是一款救星。它会让你的测试非常容易编写(你基本上用简单的英语说话:点击这个,按返回按钮等)。你可以测试任何东西,但你不需要知道细节。它至少有两大好处:你可以测试你没有源代码的应用程序,它依赖于UI,这使得它非常强大(你改变你的控制器/模型远远超过你的视图...) – tiktak

0

工作将接受的方法工作,与来自不同应用的不同活动保持,由不同的证书签名?如果不是,则Robotium是在同一应用程序内测试活动的最佳方法。

3

我为Android创建了一个录制和回放工具,并在GitHub上提供。它很容易配置和使用,不需要编程,可以在真实设备上运行(不必植根),并在播放测试时自动保存截图。

+0

这看起来有希望。对于那些没有看到这一点的人:这似乎是一个很好的解决方案来测试手势(点击,拖动和其他东西) – tiktak

1

我的工作几乎是同样的事情,我可能会与所接受的回答这个问题的变化去,但在我搜索一个我没有遇到CalculuongitHub解。

3

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

'ActivityInstrumentationTestCase2'构造函数忽略了package参数,并且不需要它。采用该包的构造函数已被弃用。

从Javadoc中: “ ActivityInstrumentationTestCase2(字符串PKG,类activityClass) 此构造已被弃用使用ActivityInstrumentationTestCase2(类),而不是”

使用建议的基类允许框架来处理某些样板,如启动你的活动。如果需要,可以通过调用“getActivity()”来完成。

3

发现这个有用的几个修改。 首先getInstrumentation().waitForIdleSync()将治愈片状SingleShot说 和InstrumentationTestCase有一个lauchActivity函数,可以取代开始活动行。

+0

谢谢,这是好东西! – icecreamman

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)); 
4

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

MonkeyTalk:由Gorilla Logic公司支持的开源工具。优点:为非技术用户提供录音和更高级的脚本语言,并且是跨平台的(包括iOS)。鉴于这些好处是需求,我们发现这是最好的解决方案。它还允许customization超出使用Javascript的脚本语言所能做的。

Calabash-Android:用于黄瓜式功能的开源工具。优点:使用商业可读的特定于领域的语言编写Gherkin语言的特性,该语言可让您描述软件的行为,而无需详细说明该行为的实施方式。 iOS的cucumber-ios中提供了类似但不完全的支持。录制功能不太好,因为它们会产生二进制输出。

一对夫妇的其他参考:

  • 这里有Robotium之间的一些additional comparisons, Monkeytalk和葫芦。它提到TestDroid作为另一个 的可能性。
  • 这个blog提到了上面加上NativeDriver和Bot-bot。
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; 
} 
-2

尝试猴工具测试

步骤1:

打开机器人工作室终端(工具 - >开端子)

步骤2:

为了使用猴子,打开一个命令提示符,然后导航到以下目录。

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

第3步:

添加这只猴子的命令到终端,然后按回车..

看到在你的模拟器的魔力。

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

+0

Downvoters必须告诉下调的原因......这是工作代码..也是正式的测试方法。如果有任何错误,我准备纠正我的答案.. –

相关问题