UiAutomator UIAutomator2.0 简介

恒温 · November 08, 2015 · Last by Forwards replied at September 04, 2018 · 14716 hits
本帖已被设为精华帖!

UIAutomator2.0 出来有一段时间了。

我们就看一句话

Most importantly, UIAutomator is now based on Android Instrumentation

Instrumentation 终于把 UIAutomator 纳入了他的麾下。

UIAutomator2.0 出来之后,投入使用的似乎不多,官方的文档也不多,而且还有错。😢 不过各个测试框架也在积极拥抱变化,比如 Appium,Selendroid。最快的极客学院也推出了 UIAutomator2.0 的教程。当然我们 TesterHome 也有同学上了一把,比如在 Android studio 上运用 UI Automator 执行自动化测试。新东西出来了,不代表旧事物就不能用了。之前的 UIAutomator 一样可以跑的很欢,守旧的同学可以继续。

事实上,Google 提供的 Android Testing Support Library 变化的挺多的,比如全面拥抱 Junit 4.0,力荐使用 AndroidJUnitRunner,然后使用 Android Studio IDE 等等。反正不仅在开发端,在测试端,Google 也在做一些标准和统一,然后让我们忘记之前的 monkeyrunner, instruments,只剩下:

  • AndroidJUnitRunner: JUnit 4-compatible test runner for Android
  • Espresso: UI testing framework; suitable for functional UI testing within an app
  • UI Automator: UI testing framework; suitable for cross-app functional UI testing across system and installed apps

废话时间结束。

如何写一个 UIAutomator2.0 的工程?

在这之前,我是这样写 UIAutomator 的, 参见如何使用和调试 android UIAutomator ?。我记性不好,就算现在写,也会翻翻自己的文章。我试着也使用 maven 来配置,不过失败告终。因为在 maven 库里面,找不到 com.android.support.test.*,因为貌似所有的测试依赖都移到这里来了。而在你电脑上,它藏在 android-sdk/extras/android/m2repository 下面,感觉上它也可以成为你 local maven 库中的一个,不过没时间研究。关于安装Android Maven 本地依赖库可以帮你开拓下思维,但是然并软。所以老老实实使用 gradle 吧。

更新下,如果不想用 gradle,想直接使用 jar 包做依赖的话,可以下载 https://github.com/googlesamples/android-testing/tree/master/ui/espresso/BasicSampleBundled/libs 下面的 jar。

创建一个 android 工程

对于 Instrumentation 大家应该都熟知,如何写一个 Instrumentation 工程,百度一搜一大把,大家模仿网上教程的时候用点心,别抄成个二百五。UIAutomator2.0 是基于 Instrumentation,所以基本上,和 Instrumentation 一样,它也有一个测试应用的概念。我们打开 AS,创建一个空应用,比如我的:

提示:Gradle 加载可能有点慢,自备 *** 会来的快一点。

添加依赖和测试代码

  1. 先在 build.grade 里面添加依赖。

    apply plugin: 'com.android.application'

    android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
    applicationId "lihuazhang.testerhome.com.uiautomator2"
    minSdkVersion 19
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" # 这是我添加的
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    }
    }

    dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.0'

    # 这以下是我添加的
    androidTestCompile 'com.android.support:support-annotations:23.1.0'
    androidTestCompile 'com.android.support.test:runner:0.4'
    // Set this dependency to use JUnit 4 rules
    androidTestCompile 'com.android.support.test:rules:0.4'
    // Set this dependency to build and run Espresso tests
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
    // Set this dependency to build and run UI Automator tests
    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

    }

  2. 在 androidTest 下面添加测试代码

    package lihuazhang.testerhome.com.uiautomator2;

    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.support.test.InstrumentationRegistry;
    import android.support.test.filters.SdkSuppress;
    import android.support.test.runner.AndroidJUnit4;
    import android.support.test.uiautomator.By;
    import android.support.test.uiautomator.UiDevice;
    import android.support.test.uiautomator.UiObject2;
    import android.support.test.uiautomator.Until;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;

    import static org.hamcrest.core.IsNull.notNullValue;
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.assertThat;

    /**
    * Created by lihuazhang on 15/11/8.
    */


    @RunWith(AndroidJUnit4.class)
    @SdkSuppress(minSdkVersion = 18)
    public class CalculatorTest {
    private UiDevice mDevice;
    private static final int LAUNCH_TIMEOUT = 5000;
    private final String BASIC_SAMPLE_PACKAGE = "com.android.calculator2";

    @Before
    public void setUp() {
    // Initialize UiDevice instance
    mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

    // Start from the home screen
    mDevice.pressHome();

    // Wait for launcher
    final String launcherPackage = getLauncherPackageName();
    assertThat(launcherPackage, notNullValue());
    mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);
    }
    @Test
    public void checkPreconditions() {
    assertThat(mDevice, notNullValue());
    }

    @Test
    public void calculatorTest() {
    mDevice.findObject(By.desc("应用")).click();
    mDevice.wait(Until.hasObject(By.desc("计算器")), LAUNCH_TIMEOUT);
    mDevice.findObject(By.desc("计算器")).click();

    UiObject2 button7 = mDevice.wait(Until.findObject(By.res("com.android.calculator2", "digit_7")), 500);
    UiObject2 buttonX = mDevice.wait(Until.findObject(By.res("com.android.calculator2", "op_mul")), 500);
    UiObject2 button6 = mDevice.wait(Until.findObject(By.res("com.android.calculator2", "digit_6")), 500);
    UiObject2 buttonEqual = mDevice.wait(Until.findObject(By.res("com.android.calculator2", "eq")), 500);
    UiObject2 output = mDevice.wait(Until.findObject(By.res("com.android.calculator2", "result")), 500);

    button7.click();
    buttonX.click();
    button6.click();
    buttonEqual.click();
    assertEquals(output.getText(), "42");

    }

    private String getLauncherPackageName() {
    // Create launcher Intent
    final Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_HOME);

    // Use PackageManager to get the launcher package name
    PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
    ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return resolveInfo.activityInfo.packageName;
    }
    }

运行

运行很简单,右击测试文件,点击运行即可。

如果在命令行的话,直接运行 ./gradlew cC

这个时候,我们打开 adb shell

那既然是 instrumentation,其实我们可以使用这样的命令来执行。

  connected  adb shell am instrument -w lihuazhang.testerhome.com.uiautomator2.test/android.support.test.runner.AndroidJUnitRunner

lihuazhang.testerhome.com.uiautomator2.CalculatorTest:..

Time: 7.014

OK (2 tests)

我没找到 uiautomator 1.0 的 nohup 形式,不知道其他人知道不。

报告

感谢 @carl 的提醒,漂亮的报告还是需要的。./gradlew cC 生成的报告在 Uiautomator2/app/build/reports/androidTests/connected 位置。

注意点

  1. 不要继承 InstrumentationTestCase

    This class is deprecated. It is no longer necessary to extend UiAutomatorTestCase. You can use getInstance(Instrumentation) from any test class as long as you have access to an Instrumentation instance.

    既然 UiAutomatorTestCase 都不用继承了,更别提 InstrumentationTestCase 了。官方文档里部分代码还在继承 InstrumentationTestCase,当然不会引起啥错误,但是在命令行使用 gradle cC 的时候,测试用例不会被执行。
    更新下,@carl 说他是继承了InstrumentationTestCase的,所以我又试验了下。gradle cC 运行的时候报错:

  2. mDevice.wait(Until.findObject(By.res("com.android.calculator2", "digit_7")), 500); 必要的等待还是需要的。众所周知,UI 自动化,如果不加入必要的等待策略,那么很难保证测试用例的鲁棒性。

  3. 我在执行测试用例的时候,使用的 Genymotion 模拟器,但是发现了一些问题,比如这个计算器的用例在 Genymotion 中无法通过。

  4. 遇到此类异常 UiAutomationService android.accessibilityservice.IAccessibilityServiceClient$Stub$Proxy@52c58464already registered!,先看看设备上是否有 uiautomator 在运行,有的话杀之。

  5. 在代码里的 System.out.println 是会输出在 logcat 的日志里。此外执行信息也会出现在 logcat 中。

参考文档

  1. UIAutomator2.0 的 API 文档
  2. Testing Support Library
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 54 条回复 时间 点赞

据我实际经验,我是继承了InstrumentationTestCase的,gradle cC是可以执行的,它是全部执行。
非继承的方式在极客学院上就是这样用的,看过了,不错的。
本文没有对执行结果描述一下,有点尴尬,毕竟结果很重要,2.0会生成一份网页的测试报告的,比1.0好很多,如果能修改生成报告的部分,根据自己的需要客制化一下就好了。

@carl 建议你再运行一次,然后看看你的 test runner 是哪个?
com.android.builder.testing.ConnectedDevice > No tests found.[Nexus 5 - 6.0] FAILED
No tests found. This usually means that your test classes are not in the form that your test runner expects (e.g. don't inherit from TestCase or lack @Test annotations).
:app:connectedDebugAndroidTest FAILED

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':app:connectedDebugAndroidTest'.

    There were failing tests. See the report at: file:///Users/lihuazhang/code/Uiautomator2/app/build/reports/androidTests/connected/index.html

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

技能 GET起来~~

uiautomator2.0让执行测试更快, 更强.是个很强大的改进. 这对appium是重大的利好.
不过传统插桩的方式仍然非常重要, 还是离不开. 兼容性测试是绕不过去的

哈哈,我宿舍电脑硬盘前几天坏了没环境,明天把公司的测试用例带回来反驳下不可以继承的观点。其实目前我最想知道的是测试报告,这个数据是怎么来的,是不是在手机某个目录下有的,又导出到了PC端,毕竟用例是在手机上跑的。它的原理是什么?有没有方法修改,比如说在原来的报告中加入更多的信息。

#5楼 @carl 可以研究下。

#5楼 @carl 测试报告是android gradle插件使用ddmlibs调用adb shell,然后分析adb shell的instrumentation log, 格式化成数据后输出成html。 可以参考android gradle插件源码

#7楼 @xiaoyy 感谢,我先去了解下,有问题再请教。

#7楼 @xiaoyy 这段代码在哪里啊?

恒温 #10 · November 12, 2015 作者

首先我们得知道,我们的报告生成的数据是在 app/build/outputs/androidTest-results/connected/xxx.xml 这个文件里。

文件名的命名:com.android.builder.internal.testing.CustomTestRunListener.java

@Override
protected File getResultFile(File reportDir) throws IOException {
return new File(reportDir,
"TEST-" + mDeviceName + "-" + mProjectName + "-" + mFlavorName + ".xml");
}

然后 CustomTestRunListener 继承于 com.android.ddmlib.testrunner.XmlTestRunListener,于是就能追到 https://android.googlesource.com/platform/tools/base/+/master/ddmlib/src/main/java/com/android/ddmlib/testrunner/XmlTestRunListener.java 里面去了。

瞧瞧看这个方法:


/**
* Creates a report file and populates it with the report data from the completed tests.
*/

private void generateDocument(File reportDir, long elapsedTime) {
String timestamp = getTimestamp();
OutputStream stream = null;
try {
stream = createOutputResultStream(reportDir);
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(stream, SdkConstants.UTF_8);
serializer.startDocument(SdkConstants.UTF_8, null);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
// TODO: insert build info
printTestResults(serializer, timestamp, elapsedTime);
serializer.endDocument();
String msg = String.format("XML test result file generated at %s. %s" ,
getAbsoluteReportPath(), mRunResult.getTextSummary());
Log.logAndDisplay(LogLevel.INFO, LOG_TAG, msg);
} catch (IOException e) {
Log.e(LOG_TAG, "Failed to generate report data");
// TODO: consider throwing exception
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException ignored) {
}
}
}
}

就是说每次执行都会把结果记录在 mRunResult 里,到结束后,写入到结果中去。

@carl

#10楼 @lihuazhang 插件是在类CustomTestRunListener先生成xml, 然后TestReport类转换为可视化的html文档. 前两天没上testerhome 没有回复 不好意思

恒温 #12 · November 13, 2015 作者

#11楼 @xiaoyy 我已经找到了。多谢。

#12楼 @lihuazhang 这个是不是需要源码?

恒温 #14 · November 13, 2015 作者

#13楼 @babyshine 。。。你看完帖子了吗?

#14楼 @lihuazhang 跟我之前做的不太一样,我那个是打成jar包,然后就只写case,没有app源码这部分

恒温 #16 · November 13, 2015 作者

#15楼 @babyshine 我测试的是计算器,你看到我用计算器的源码了吗?

#16楼 @lihuazhang 这倒是没有,不错不错

#17楼 @babyshine 我给你们之后这回复跪了。。。

#18楼 @monkey 两年前用uiautomator 了,还以为升级了

#16楼 @lihuazhang @babyshine 虽然不用计算器的源码. 但是instrumenration倒是需要一个宿主工程. 和uiautomator不一样的地方

旧的uiautomator版本getcurrentActivity()返回不正确,2.0修复这个问题了吗?
或者有其他的方式能得到当前页面的activity name吗?

求教eclipse的教程,执行一直失败
[2015-12-02 10:41:44 - lijingwu] ------------------------------
[2015-12-02 10:41:44 - lijingwu] Android Launch!
[2015-12-02 10:41:44 - lijingwu] adb is running normally.
[2015-12-02 10:41:44 - lijingwu] Performing android.test.InstrumentationTestRunner JUnit launch
[2015-12-02 10:41:44 - lijingwu] Automatic Target Mode: using device 'd84e272b'
[2015-12-02 10:41:44 - lijingwu] WARNING: Application does not specify an API level requirement!
[2015-12-02 10:41:44 - lijingwu] Device API version is 19 (Android 4.4.4)
[2015-12-02 10:41:44 - lijingwu] Uploading lijingwu.apk onto device 'd84e272b'
[2015-12-02 10:41:45 - lijingwu] Installing lijingwu.apk...
[2015-12-02 10:41:54 - lijingwu] Success!
[2015-12-02 10:41:54 - lijingwu] Launching instrumentation android.test.InstrumentationTestRunner on d84e272b
[2015-12-02 10:41:54 - lijingwu] Failed to launch test

恒温 #23 · December 02, 2015 作者

#22楼 @lijingwu eclipse 没用过啊。 你能说说你具体怎么部署的嘛?

#23楼 @lihuazhang

这是我的工程文件,代码是copy你的教程里面的,

这是.xml文件内容

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android_test_demo.test.test"
android:versionCode="32"
android:versionName="32.0" >

<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android_test_demo.test.test" />

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>

</manifest>
25Floor has been deleted
26Floor has been deleted
恒温 #27 · December 03, 2015 作者

#24楼 @lijingwu runner 不对

使用uiautomator+gradle生成的报告比较简洁,有没有方法加入一些日志信息到报告中!求解!非常感谢

这个是不是不支持4.2的手机啊

#11楼 @xiaoyy 请教一个问题:怎么向增加一些用户自定义信息?我使用log.i() / log.e() system.out.println()来输入用户自定义信息,为什么都没有从html中找到?

#28楼 @ouguangqian 这个问题找到解决方法了么?我自己试着用log.i() 和 system.out.println()都不行

请教:UiAutomatorTestCase不继承后,如何实现teardown?现在每条case跑完后,直接停留在最后的页面,没有关闭应用。这对case的独立性是不利的。谢谢!

恒温 #33 · January 06, 2016 作者

#32楼 @kx5156 自己不能写 teardown 吗?

#33楼 @lihuazhang 把InstrumentationTestCase中的tearDown的实现 copy过来,不起作用;通过java执行“adb shell am force-stop xxx”也关不掉。

@lihuazhang 请教一个问题,是用uiautomatorviewer查看元素的时候,应该可以看见webview的内容,但是我这却看不到,能帮忙解决一下不?

#10楼 @lihuazhang 你用的runner是哪个?为什么我没有找到对CustomTestRunListener的添加呢?

各位大神,为什么我通过UiObject2 obj = mDevice.findObject(By.text("应用")); 找出来的对象是null啊,我的虚拟机也是geny。而且也到了桌面home了。 在@Test的方法第一行运行这代码是null

38Floor has been deleted

学习uiautomator2.0有一段时间了,目前想真正测一下APP,但是遇到一个问题:怎么在android Studio里部署整个项目呢,比如方法的封装,控件的定位,用例等等,自己没有一个清晰的思路,哪位大神可以把自己uiautomator2的测试框架告知一下,以备借鉴,十分感谢,小弟初学,比较菜,请多指教

恒温 #40 · June 18, 2016 作者

#39楼 @xxb 你是想学 android app 开发吧。。

#40楼 @lihuazhang 不是 我就是想学习一下整个测试框架的部署,目前没有一个清晰的思路,不知道大家用uiautomator2的时候整个测试项目是如何部署的

我如果要知道"開啟app"要花費多少時間(response time),是不是可以用mDevice.wait()去實現?

@Test
public void openApp(){
long startTime = System.nanoTime();

//open the app
Context context = InstrumentationRegistry.getContext();
final Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
//Clear out any previous instances
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);

// Wait for the app to appear
mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT);

long endTime = System.nanoTime();

Log.w(LOG_TAG, (endTime - startTime));
}

Logcat顯示出的時間差就會是我要的response time? 點擊按鈕切換介面也可以這樣做嗎?
另外我看了文件還不是很理解為什麼要有“LAUNCH_TIMEOUT”

大神们,亲爱的大神们,2.0支持Context吗,可以再2.0的自动化代码中实现发送广播不~不胜感谢~

#43楼 @testblue 完全可以啊,拿到Context啊。 getInstrumentation().getContext 就 可以了。。
但是 发广播 用辅助的APK 弹通知,实在是没有必要

#44楼 @gybin02 是这样啊,因为我需要在完成一个自动话后告诉另一个服务它已经完成,那就需要给这个服务发送一个广播告诉它,是这么个意思~

#1楼 @carl 你好! 我这里执行命令行(terminal)gradle Cc 时 编译出错,如下(直接在AS运行测试工程正常):怎么解决,麻烦了
FAILURE: Build failed with an exception.

  • What went wrong:
    A problem occurred configuring project ':app'.

    org.gradle.api.internal.tasks.DefaultTaskInputs$TaskInputUnionFileCollection cannot be cast to org.gradle.api.internal.file.collections.DefaultConfigur
    ableFileCollection

  • Try:
    Run with --info or --debug option to get more log output.

  • Exception is:
    org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':app'.
    at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:79)
    at org.gradle.configuration.project.LifecycleProjectEvaluator.notifyAfterEvaluate(LifecycleProjectEvaluator.java:74)
    at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:61)
    at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:573)
    at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:125)
    at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:47)
    at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:38)
    at org.gradle.initialization.DefaultGradleLauncher$2.run(DefaultGradleLauncher.java:124)
    at org.gradle.internal.Factories$1.create(Factories.java:22)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:121)
    at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
    at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
    at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:94)
    at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
    at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:43)
    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:28)
    at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:82)
    at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
    at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:59)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:49)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
    at org.gradle.util.Swapper.swap(Swapper.java:38)
    at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
    at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.HintGCAfterBuild.execute(HintGCAfterBuild.java:44)
    at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
    at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
    at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:240)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    Caused by: java.lang.ClassCastException: org.gradle.api.internal.tasks.DefaultTaskInputs$TaskInputUnionFileCollection cannot be cast to org.gradle.api.in
    ternal.file.collections.DefaultConfigurableFileCollection
    at com.android.build.gradle.tasks.factory.UnitTestConfigAction.fixTestTaskSources(UnitTestConfigAction.java:168)
    at com.android.build.gradle.tasks.factory.UnitTestConfigAction.execute(UnitTestConfigAction.java:92)
    at com.android.build.gradle.tasks.factory.UnitTestConfigAction.execute(UnitTestConfigAction.java:49)
    at org.gradle.api.internal.tasks.DefaultTaskContainer.create(DefaultTaskContainer.java:128)
    at com.android.build.gradle.internal.TaskContainerAdaptor.create(TaskContainerAdaptor.java:59)
    at com.android.build.gradle.internal.scope.AndroidTaskRegistry.create(AndroidTaskRegistry.java:46)
    at com.android.build.gradle.internal.scope.AndroidTaskRegistry.create(AndroidTaskRegistry.java:81)
    at com.android.build.gradle.internal.TaskManager.createRunUnitTestTask(TaskManager.java:1529)
    at com.android.build.gradle.internal.TaskManager.createUnitTestVariantTasks(TaskManager.java:1276)
    at com.android.build.gradle.internal.VariantManager.createTasksForVariantData(VariantManager.java:450)
    at com.android.build.gradle.internal.VariantManager$3.call(VariantManager.java:291)
    at com.android.build.gradle.internal.VariantManager$3.call(VariantManager.java:288)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:55)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:47)
    at com.android.build.gradle.internal.profile.SpanRecorders.record(SpanRecorders.java:51)
    at com.android.build.gradle.internal.VariantManager.createAndroidTasks(VariantManager.java:287)
    at com.android.build.gradle.BasePlugin$12.call(BasePlugin.java:661)
    at com.android.build.gradle.BasePlugin$12.call(BasePlugin.java:658)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:55)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:47)
    at com.android.build.gradle.BasePlugin.createAndroidTasks(BasePlugin.java:657)
    at com.android.build.gradle.BasePlugin$10$1.call(BasePlugin.java:571)
    at com.android.build.gradle.BasePlugin$10$1.call(BasePlugin.java:568)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:55)
    at com.android.builder.profile.ThreadRecorder$1.record(ThreadRecorder.java:47)
    at com.android.build.gradle.BasePlugin$10.execute(BasePlugin.java:567)
    at com.android.build.gradle.BasePlugin$10.execute(BasePlugin.java:564)
    at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:93)
    at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:82)
    at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:44)
    at org.gradle.internal.event.BroadcastDispatch.dispatch(BroadcastDispatch.java:79)
    at org.gradle.internal.event.BroadcastDispatch.dispatch(BroadcastDispatch.java:30)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy13.afterEvaluate(Unknown Source)
    at org.gradle.configuration.project.LifecycleProjectEvaluator.notifyAfterEvaluate(LifecycleProjectEvaluator.java:67)
    ... 52 more

BUILD FAILED

Total time: 1.675 secs

#46楼 @anyin
我测试时一直都是用AS直接运行的,从命令行编译的只是在最开始试过,后来没有用过了,这里的错误(坑)我没有碰到(踩)过,我的建议是:检查命令行的gradle版本是否与AS一致,另外检查AS是否有设置代理,更多错误信息还是搜索一下吧,gradle Caused by: java.lang.ClassCastException

@Lihuazhang 您好,我这里没有测试没有问题,但是没有 instrumentation,请问是什么原因呢?

@Lihuazhang 请问一下 如何后台执行,拔掉usb后执行不中断,类似于Uiautomator1中的 --nohup

恒温 #51 · March 01, 2017 作者

adb shell nohup am instrument -w ...

定义的计算器包名常量BASIC_SAMPLE_PACKAGE,启动时没有使用呢?

To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/2.14.1/userguide/gradle_daemon.html.

FAILURE: Build failed with an exception.

  • What went wrong:
    Unable to start the daemon process.
    This problem might be caused by incorrect configuration of the daemon.
    For example, an unrecognized jvm option is used.
    Please refer to the user guide chapter on the daemon at https://docs.gradle.org/2.14.1/userguide/gradle_daemon.html

    Please read the following process output to find out more:

    Error occurred during initialization of VM
    Could not reserve enough space for object heap
    Error: Could not create the Java Virtual Machine.
    Error: A fatal exception has occurred. Program will exit.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

运行gradlew.bat cC是 ,报不能吊起虚拟机,怎么解决啊

您好,我出现这样的问题弄了好久都没办法解决,请问能帮我看看吗?谢谢
junit.framework.AssertionFailedError: Exception in constructor: testDemo (java.lang.RuntimeException: Stub!
at com.android.uiautomator.testrunner.UiAutomatorTestCase.(UiAutomatorTestCase.java:5)
at com.example.administrator.myapplication.TestCalculator.(TestCalculator.java:10)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:430)
at junit.framework.TestSuite.createTest(TestSuite.java:61)
at junit.framework.TestSuite.addTestMethod(TestSuite.java:294)
at junit.framework.TestSuite.addTestsFromTestCase(TestSuite.java:150)
at junit.framework.TestSuite.(TestSuite.java:129)
at android.support.test.internal.runner.junit3.NonLeakyTestSuite.(NonLeakyTestSuite.java:34)
at android.support.test.internal.runner.junit3.AndroidTestSuite.(AndroidTestSuite.java:49)
at android.support.test.internal.runner.junit3.AndroidJUnit3Builder.runnerForClass(AndroidJUnit3Builder.java:52)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runner.Computer.getRunner(Computer.java:40)
at org.junit.runner.Computer$1.runnerForClass(Computer.java:31)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:101)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:87)
at org.junit.runners.Suite.(Suite.java:81)
at org.junit.runner.Computer.getSuite(Computer.java:28)
at android.support.test.internal.runner.TestRequestBuilder.classes(TestRequestBuilder.java:789)
at android.support.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:753)
at android.support.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:354)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:260)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1932)
)
at junit.framework.Assert.fail(Assert.java:50)
at junit.framework.TestSuite$1.runTest(TestSuite.java:97)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:115)
at android.support.test.internal.runner.junit3.AndroidTestResult.runProtected(AndroidTestResult.java:77)
at junit.framework.TestResult.run(TestResult.java:118)
at android.support.test.internal.runner.junit3.AndroidTestResult.run(AndroidTestResult.java:55)
at junit.framework.TestCase.run(TestCase.java:124)
at android.support.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest.run(NonLeakyTestSuite.java:63)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at android.support.test.internal.runner.junit3.DelegatingTestSuite.run(DelegatingTestSuite.java:103)
at android.support.test.internal.runner.junit3.AndroidTestSuite.run(AndroidTestSuite.java:69)
at android.support.test.internal.runner.junit3.JUnit38ClassRunner.run(JUnit38ClassRunner.java:103)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1932)

Tests ran to completion.

我的build.gradle是这样的

apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.example.administrator.myapplication"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha7'
testCompile 'junit:junit:4.12'
compile files('libs/uiautomator.jar')
}

charles0427 UiAutomator2 Server 运行原理分析 中提及了此贴 05 Jul 14:50

用命令执行才能生成报告,如何使用gradlew命令 或者am insturment来运行指定文件夹里的case?我用这个命令:gradlew connectedAndroidTest 运行的是所有测试类,但是我的框架分两个文件夹,一个回归,一个性能,如果指定文件夹呢?

恒温 [Topic was deleted] 中提及了此贴 23 Apr 23:10

请问有没有uiautomator 脱离PC(apk启动)的教程???

xinxi Android Uiautomator2 脱机 Monkey 测试 中提及了此贴 24 Apr 22:26
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up