💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
> 编写:[huanglizhuo](https://github.com/huanglizhuo) - 原文:[http://developer.android.com/training/](http://developer.android.com/training/activity-testing/activity-functional-testing.html)[activity](# "An activity represents a single screen with a user interface.")-testing/[activity](# "An activity represents a single screen with a user interface.")-functional-testing.html 功能测试包括验证单个应用中的各个组件是否与使用者期望的那样(与其它组件)协同工作。比如,我们可以创建一个功能测试验证在用户执行UI交互时[Activity](# "An activity represents a single screen with a user interface.")是否正确启动目标[Activity](# "An activity represents a single screen with a user interface.")。 要为[Activity](# "An activity represents a single screen with a user interface.")创建功能测,我们的测试类应该对[ActivityInstrumentationTestCase2](http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html)进行扩展。与[ActivityUnitTestCase](http://developer.android.com/reference/android/test/ActivityUnitTestCase.html)不同,[ActivityInstrumentationTestCase2](http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html)中的测试可以与Android系统通信,发送键盘输入及点击事件到UI中。 要了解一个完整的测试例子可以参考示例应用中的`SenderActivityTest.java`。 ### 添加测试方法验证函数的行为 我们的函数测试目标应该包括: - 验证UI控制是否正确启动了目标[Activity](# "An activity represents a single screen with a user interface.")。 - 验证目标[Activity](# "An activity represents a single screen with a user interface.")的表现是否按照发送[Activity](# "An activity represents a single screen with a user interface.")提供的数据呈现。 我们可以这样实现测试方法: ~~~ @MediumTest public void testSendMessageToReceiverActivity() { final Button sendToReceiverButton = (Button) mSenderActivity.findViewById(R.id.send_message_button); final EditText senderMessageEditText = (EditText) mSenderActivity.findViewById(R.id.message_input_edit_text); // Set up an ActivityMonitor ... // Send string input value ... // Validate that ReceiverActivity is started ... // Validate that ReceiverActivity has the correct data ... // Remove the ActivityMonitor ... } ~~~ 测试会等待匹配的[Activity](# "An activity represents a single screen with a user interface.")启动,如果超时则会返回null。如果ReceiverActivity启动了,那么先前配置的[ActivityMoniter](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html)就会收到一次碰撞(Hit)。我们可以使用断言方法验证ReceiverActivity是否的确启动了,以及[ActivityMoniter](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html)记录的碰撞次数是否按照预想地那样增加。 ### 设立一个ActivityMonitor 为了在应用中监视单个[Activity](# "An activity represents a single screen with a user interface.")我们可以注册一个[ActivityMoniter](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html)。每当一个符合要求的[Activity](# "An activity represents a single screen with a user interface.")启动时,系统会通知[ActivityMoniter](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html),进而更新碰撞数目。 通常来说要使用[ActivityMoniter](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html),我们可以这样: 1. 使用[getInstrumentation()](http://developer.android.com/reference/android/test/InstrumentationTestCase.html#getInstrumentation())方法为测试用例实现[Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html)。 1. 使用[Instrumentation](http://developer.android.com/reference/android/app/Instrumentation.html)的一种addMonitor()方法为当前instrumentation添加一个[Instrumentation.ActivityMonitor](http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html)实例。匹配规则可以通过[IntentFilter](http://developer.android.com/reference/android/content/IntentFilter.html)或者类名字符串。 1. 等待开启一个[Activity](# "An activity represents a single screen with a user interface.")。 1. 验证监视器撞击次数的增加。 1. 移除监视器。 下面是一个例子: ~~~ // Set up an ActivityMonitor ActivityMonitor receiverActivityMonitor = getInstrumentation().addMonitor(ReceiverActivity.class.getName(), null, false); // Validate that ReceiverActivity is started TouchUtils.clickView(this, sendToReceiverButton); ReceiverActivity receiverActivity = (ReceiverActivity) receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS); assertNotNull("ReceiverActivity is null", receiverActivity); assertEquals("Monitor for ReceiverActivity has not been called", 1, receiverActivityMonitor.getHits()); assertEquals("Activity is of wrong type", ReceiverActivity.class, receiverActivity.getClass()); // Remove the ActivityMonitor getInstrumentation().removeMonitor(receiverActivityMonitor); ~~~ ### 使用Instrumentation发送一个键盘输入 如果[Activity](# "An activity represents a single screen with a user interface.")有一个[EditText](http://developer.android.com/reference/android/widget/EditText.html),我们可以测试用户是否可以给[EditText](http://developer.android.com/reference/android/widget/EditText.html)对象输入数值。 通常在[ActivityInstrumentationTestCase2](http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html)中给[EditText](http://developer.android.com/reference/android/widget/EditText.html)对象发送串字符,我们可以这样做: 1. 使用[runOnMainSync()](http://developer.android.com/reference/android/app/Instrumentation.html#runOnMainSync(java.lang.Runnable))方法在一个循环中同步地调用[requestFocus()](http://developer.android.com/reference/android/view/View.html#requestFocus())。这样,我们的UI线程就会在获得焦点前一直被阻塞。 1. 调用[waitForIdleSync()](http://developer.android.com/reference/android/app/Instrumentation.html#waitForIdleSync())方法等待主线程空闲(也就是说,没有更多事件需要处理)。 1. 调用[sendStringSync()](http://developer.android.com/reference/android/app/Instrumentation.html#sendStringSync(java.lang.String))方法给[EditText](http://developer.android.com/reference/android/widget/EditText.html)对象发送一个我们输入的字符串。 比如: ~~~ // Send string input value getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { senderMessageEditText.requestFocus(); } }); getInstrumentation().waitForIdleSync(); getInstrumentation().sendStringSync("Hello Android!"); getInstrumentation().waitForIdleSync(); ~~~ 本节例子[AndroidTestingFun.zip](http://developer.android.com/shareables/training/AndroidTestingFun.zip)