我们正在构建一个使用Appium进行测试的Android应用。现在我想看看Appium测试的测试覆盖率。 我认为这是可能的,因为Jacoco支持离线工具(http://www.eclemma.org/jacoco/trunk/doc/offline.html)。
甚至jacoco gradle插件的文档都说:
虽然在应用java插件时,所有类型为Test的任务都会自动增强以提供覆盖信息,但JaCoCo插件可以增强任何实现JavaForkOptions的任务。也就是说,任何分叉Java进程的任务都可用于生成覆盖信息。
请参阅https://docs.gradle.org/current/userguide/jacoco_plugin.html
但是我如何编写build.gradle以便检测我们的验收调试风格,并在执行Appium测试或执行手动测试用例时将exec文件写入Smartphone? 因为那时我可以提取exec文件并将其发送给SonarQube进行进一步分析。
由于 本
答案 0 :(得分:1)
最后,我设法让它工作,我想和你分享解决方案:
为您的buildType启用检测并相应地配置SonarQube e.g。
...
apply plugin: 'jacoco'
...
android {
...
productFlavors {
acceptance {
applicationId packageName + ".acceptance"
buildTypes {
debug {
testCoverageEnabled true
}
}
}
}
}
sonarRunner {
sonarProperties {
property "sonar.host.url", "..."
property "sonar.jdbc.url", sonarDatabaseUrl
property "sonar.jdbc.driverClassName", sonarDatabaseDriverClassName
property "sonar.jdbc.username", sonarDatabaseUsername
property "sonar.jdbc.password", sonarDatabasePassword
property "sonar.sourceEncoding", "UTF-8"
property "sonar.sources", "src/main"
property "sonar.tests", "src/test"
property "sonar.inclusions", "**/*.java,**/*.xml"
property "sonar.import_unknown_files", "true"
property "sonar.java.binaries", "build/intermediates/classes/acceptance/debug"
property "sonar.junit.reportsPath", "build/test-results/acceptanceDebug"
property "sonar.android.lint.report", "build/outputs/lint-results.xml"
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.jacoco.reportPath", "build/jacoco/testAcceptanceDebugUnitTest.exec"
// see steps below on how to get that file:
property "sonar.jacoco.itReportPath", "build/jacoco/jacoco-it.exec"
property "sonar.projectKey", projectKey
property "sonar.projectName", projectName
property "sonar.projectVersion", appVersionName
}
}
将以下内容添加到AndroidManifest.xml
<receiver
android:name=".util.CoverageDataDumper"
tools:ignore="ExportedReceiver">
<intent-filter>
<action android:name="org.example.DUMP_COVERAGE_DATA"/>
</intent-filter>
</receiver>
CoverageDataDumper应如下所示:
public class CoverageDataDumper extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger( CoverageDataDumper.class );
@Override
public void onReceive( Context context, Intent intent ) {
try {
Class
.forName( "com.vladium.emma.rt.RT" )
.getMethod( "dumpCoverageData", File.class, boolean.class, boolean.class )
.invoke( null,
new File( App.getContext().getExternalFilesDir( null ) + "/coverage.ec" ),
true, // merge
false // stopDataCollection
);
}
catch ( Exception e ) {
LOG.error( "Error when writing coverage data", e );
}
}
}
然后使用Accept flavor app(带有检测类)运行Appium测试用例。在你打电话之前#34;重置应用程序&#34;或&#34;关闭申请&#34;确保调用以下方法(只是草稿,但我认为你明白了):
// intent is "org.example.DUMP_COVERAGE_DATA"
public void endTestCoverage( String intent ) {
if ( driver instanceof AndroidDriver ) {
((AndroidDriver) driver).endTestCoverage( intent, "" );
}
}
public void pullCoverageData( String outputPath ) {
String coverageFilePath = (String) appiumDriver.getCapabilities().getCapability( "coverageFilePath" );
if ( coverageFilePath != null ) {
byte[] log = appiumDriver.pullFile( coverageFilePath );
MobileAppLog.writeLog( new File( outputPath ), log );
}
else {
throw new AppiumLibraryNonFatalException(
"Tried to pull the coverage data, but the coverageFilePath wasn't specified." );
}
}
outputPath可以是例如:/sdcard/Android/data/org.example.acceptance/files/coverage.ec
现在,Jacoco数据被写入智能手机。接下来我们需要下载该文件。你可以使用
appiumDriver.pullFile( logFilePath );
现在你需要复制文件&#34; jacoco-it.exec&#34; (当你拉文件时应该追加)到build / jacoco / jacoco-it.exec中,请参阅上面的gradle.build并运行
gradlew sonarRunner
在SonarQube中添加Integration Test Coverage Widget,你现在应该看到一些值......
不幸的是,如果您使用retrolambda(我们这样做),代码覆盖率将无法正常工作。 Retrolambda将生成不属于源文件的匿名类 - 因此SonarQube无法正确匹配它们并显示比实际更低的代码覆盖率。如果有人找到了解决方案,我会非常高兴: - )
答案 1 :(得分:0)
我通过向您测试的应用程序添加广播接收器解决了这个问题! (您只能将接收器添加到调试文件夹,因此不需要它存在于主源中)
public class CoverageReceiver extends BroadcastReceiver {
private static final String EXEC_FILE_PATH = "/mnt/sdcard/coverage.exec";
private static final String TAG = "CoverageJacoco";
private static final String BROADCAST_RECEIVED_MESSAGE = "EndJacocoBroadcast broadcast received!";
private static final String EMMA_CLASS = "com.vladium.emma.rt.RT";
private static final String EMMA_DUMP_METHOD = "dumpCoverageData";
@Override
public void onReceive(Context context, Intent intent) {
try {
Log.d(TAG, BROADCAST_RECEIVED_MESSAGE);
Class.forName(EMMA_CLASS)
.getMethod(EMMA_DUMP_METHOD, File.class, boolean.class,
boolean.class)
.invoke(null, new File(EXEC_FILE_PATH), true,
false);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
}
在manefist中添加(你可以添加这个调试文件夹,使其不存在于主源中)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<receiver android:name=".CoverageReceiver">
<intent-filter>
<action android:name="com.example.action" />
</intent-filter>
</receiver>
</application>
在我添加的应用程序的build.gradle中
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.4+"
}
model {
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.example.app"
minSdkVersion.apiLevel 23
targetSdkVersion.apiLevel 23
versionCode 12
versionName "1.11"
}
buildTypes {
debug {
testCoverageEnabled true
}
}
您将应用程序构建为调试,而不是安装并运行它。
通过ADB“adb shell am broadcast -a com.example.action”发送广播来创建coverage.exec 从设备拉取覆盖率 - adb pull /mnt/sdcard/coverage.exec
运行此操作后,您需要从文件
创建coverage **
* This task is used to create a code coverage report via the Jcoco tool.
*/
task jacocoTestReport(type: JacocoReport) {
def coverageSourceDirs = [
'src/main/java',
]
group = "Reporting"
description = "Generates Jacoco coverage reports"
reports {
csv.enabled false
xml{
enabled = true
destination "${buildDir}/jacoco/jacoco.xml"
}
html{
enabled true
destination "${buildDir}/jacocoHtml"
}
}
classDirectories = fileTree(
dir: 'build/intermediates/classes',
excludes: ['**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Activity*.*',
'**/*Fragment*.*'
]
)
sourceDirectories = files(coverageSourceDirs)
executionData = files('build/coverage.exec')
}
此任务是创建覆盖文件的一种方法 在coverageSourceDirs中添加应用程序源代码的所有位置,因此它将知道要采用哪些代码并根据它们创建覆盖 executionData是您放置从设备中提取的coverage.exec的位置
运行任务 这些文件将为html和xml创建,你也可以添加csv(注意它将在应用程序的build文件夹中创建)!
需要知道,您必须针对构建应用程序调试版本的相同代码运行任务