背景
在Android Settings 单元测试 | Telephony Network 模块 APN 案例中粗略介绍了单元测试逻辑内容,但是在独立APK里面如何将单元测试跑起来还是有疑问,因为APP不能直接install,无法借助Android Studio直接Run,在安装的一步会报错由于未签名。
> Task :connectedDebugAndroidTest FAILED
Exception thrown during onBeforeAll invocation of plugin AndroidTestApkInstallerPlugin: ErrorName: INSTALL_FAILED_UPDATE_INCOMPATIBLENameSpace: DdmlibAndroidDeviceController
ErrorCode: 1
ErrorType: TEST
Message: Failed to install split APK(s): [E:\code\DemoUnit\build\intermediates\apk\debug\DemoUnit.apk]
Failed to install split APK(s): [E:\code\DemoUnit\build\intermediates\apk\debug\DemoUnit.apk]
Failed to commit install session 396951782 with command package install-commit 396951782. Error: INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.demo.unit signatures do not match newer version; ignoring!
com.android.ddmlib.InstallException: Failed to commit install session 396951782 with command package install-commit 396951782. Error: INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.demo.unit signatures do not match newer version; ignoring!
因为是签名限制的问题,就考虑尝试使用debug版本,将没有签名的APK push到system/priv-app目录下重启使之生效,结果无法正常开机,因此这个方法是不可行的。
甚至在开机过程PMS都没有起来,执行adb install 命令是返回“cmd: Can't find service: package”。
然后把debug未签名的apk删除以后,就算没有原本的apk也能直接正常开机。
androidTest 和 test 目录说明
在 Android 项目中,测试分为两类:单元测试和仪器测试(Instrumentation Tests)。它们分别存放在不同的目录中,执行方式也不同。
1. 单元测试
- 存放位置:
src/test/java/
目录下 - 这些测试通常使用 JUnit 运行,并不能在 Android 设备或模拟器中运行。它们是在本地 JVM 中运行的。
- 要运行这些测试,可以使用 Gradle 命令:
./gradlew test
Note:上面的命令要运行成功的话,必须配置好本地环境。
2. 仪器测试 (Instrumentation Tests)
- 存放位置:
src/androidTest/java/
目录下 - 这些测试专为在 Android 设备或模拟器上运行而设计,通常用来测试应用的 UI 或与 Android 框架的交互。
- 你可以使用 ADB(Android Debug Bridge)来运行这些仪器测试。通过以下命令可以运行特定的测试类:
adb shell am instrument -w -r -e debug false -e class com.example.yourpackage.YourTestClass com.example.yourpackage.test/androidx.test.runner.AndroidJUnitRunner
3. 使用 Gradle 运行仪器测试
- 更常见和方便的方式是使用 Gradle 来运行仪器测试。例如:
./gradlew connectedAndroidTest
- 该命令会在连接的 Android 设备或模拟器上运行所有的仪器测试。
总结
- 单元测试不能通过 ADB 运行;应在本地 JVM 中运行。
- 仪器测试可以通过 ADB 运行,或者更常用的方式是通过 Gradle 命令运行。确保测试代码放在正确的目录中。在开发中通常会将仪器测试与代码的功能测试结合使用,以便进行更全面的应用测试。
如何运行Unit Test?
在test目录直接选择Test文件Run即可。
运行androidTest(UI/仪器测试)
包含androidTest测试逻辑的APK安装到了软件怎么用命令跑单元测试?——其实这个问题是不正确的,如上节说明,这应该属于UI测试。
假设应用的包名为
com.example.myapp
,测试类为
ExampleInstrumentedTest
,执行所有测试的方法可以用以下命令:
adb shell am instrument -w -r -e debug false -e class <your.package.name.YourTestClass> <your.package.name.test/androidx.test.runner.AndroidJUnitRunner>
# <your.package.name.YourTestClass>: 替换为你想要执行的测试类的全名。
# <your.package.name.test/androidx.test.runner.AndroidJUnitRunner>:
# 是测试 APK 的包名,后面加上 androidx.test.runner.AndroidJUnitRunner。
如:
案例1:
adb shell am instrument -w -r -e debug false -e class com.demo.unit.ExampleInstrumentedTest**com.demo.unit.test/androidx.test.runner.AndroidJUnitRunner
Note:斜体是需要替换的包名
- com.demo.unit.ExampleInstrumentedTest 是代码类packages包名,在java文件头定义的
- *com.demo.unit.test *是应用包名,可以通过pm查看,是在build.gradle有定义的applicationId - 如果应用是一个插件,也不用换成宿主的包名。
案例2:
adb shell am instrument -w -r -e debug false -e class com.demo.settings.PreferenceTest com.demo.unit/androidx.test.runner.AndroidJUnitRunner
Note:
- 单元测试是包名是com.demo.unit,通过pm path可查路径。
- 代码路径包名是com.demo.settings,测试类为PreferenceTest.java。
这种执行结果虽然fail了,但是说明命令是成功的。
如果只想执行某个特定的测试方法,可以通过如下命令:
adb shell am instrument -w -r -e debug false -e class <your.package.name.YourTestClass#yourTestMethod> <your.package.name.test/androidx.test.runner.AndroidJUnitRunner>
# yourTestMethod: 替换为想要执行的测试方法的名称。
常见问题
问题1:
运行命令报错,表示 Android 系统无法找到指定的测试 Runner。这通常意味着测试 Runner 没有在
AndroidManifest.xml
中正确声明,或者测试 APK 没有被正确安装。
INSTRUMENTATION_STATUS: Error=Unable to find instrumentation info for: ComponentInfo{com.demo.unit/androidx.test.runner.AndroidJUnitRunner}
解决方案:在AndroidManifest.xml 添加
AndroidJUnitRunner
声明。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
coreApp="true"
package="com.android.settings"
android:sharedUserId="android.uid.system">
<uses-sdk android:minSdkVersion="28" />
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.demo.unit" />
并通过如下命令确保应用已经安装
adb shell pm list packages | grep com.demo.unit
问题2:
android.util.AndroidException: INSTRUMENTATION_FAILED: com.demo.unit/androidx.test.runner.AndroidJUnitRunner
at com.android.commands.am.Instrument.run(Instrument.java:543)
at com.android.commands.am.Am.runInstrument(Am.java:213)
at com.android.commands.am.Am.onRun(Am.java:85)
at com.android.internal.os.BaseCommand.run(BaseCommand.java:62)
at com.android.commands.am.Am.main(Am.java:54)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:394)
测试报告
adb 命令执行的单元测试不像在android studio 里面跑的(),不能直接生成可视化的测试报告,只能通过打印文本结果,在原本命令追加输出打印。
adb shell am instrument -w -r -e debug false -e class com.demo.settings.PreferenceTest com.demo.unit/androidx.test.runner.AndroidJUnitRunner > test_result.txt
如何编写单元测试?
能参考Google的套件包实现吗?
如何查看单元测试覆盖率?
1、添加测试依赖项
在
build.gradle
(模块级)文件中,确保已包含测试相关的依赖项,例如:
dependencies {
testImplementation 'junit:junit:4.+'
testImplementation 'org.mockito:mockito-core:3.+'
// 其他依赖
}
2、启用代码覆盖率工具
在 Android Studio 中,可以通过以下方式启用代码覆盖率:
- 在菜单栏中,选择
Run
>Edit Configurations...
。 - 选择要测试的配置(例如,JUnit),在配置窗口中勾选
Code coverage
选项。、
实测找不到这个选项,执行的时候可以查看 “Cover” 工具栏,见后续第4点。
3、运行测试并生成覆盖率报告
右键点击测试类或方法,从弹出菜单中选择
Run 'YourTest' with Coverage
。运行单元测试,并生成覆盖率报告。
4、查看覆盖率报告
- 测试完成后,Android Studio 会自动打开 "Coverage" 视图,可以在这里查看覆盖率结果。
- 在 "Coverage" 视图中,将看到各个类和方法的覆盖率百分比,以及行覆盖率和语句覆盖率。
- 还能够在代码编辑器中查看覆盖率结果,覆盖的行通常会以绿色高亮显示,而未覆盖的行会以红色高亮显示。
实测步骤:
- 右键Test文件,选择 Run "xxx" with Coverage,会自动打开 “Cover” 工具栏 "Coverage" 视图。
Cover - Coverage
5、生成 HTML 覆盖率报告(可选)
如果希望生成详细的 HTML 覆盖率报告,可以在项目根目录下运行 Gradle 命令,生成报告:
./gradlew connectedAndroidTest --coverage
报告通常会生成在
build/reports/coverage
目录下,可以用浏览器打开并查看详细的覆盖率信息。
版权归原作者 Dic- 所有, 如有侵权,请联系我们删除。