前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android如何精准化测试?

Android如何精准化测试?

作者头像
测试加
发布2022-03-24 16:11:53
6530
发布2022-03-24 16:11:53
举报
文章被收录于专栏:用户4624600的专栏

前言

最近搞了一个基于jacoco统计Android代码覆盖率测试的功能,可以统计每天手工测试的代码覆盖率.自己也学习一下jacoco,陆陆续续搞了三天终于有点结果了.

本文介绍仅仅在源码中加入少量代码就可以完成代码覆盖率测试.

代码配置

build.gradle

在app目录下的build.gradle配置jacoco

代码语言:javascript
复制
apply plugin: 'jacoco'
jacoco {
    toolVersion = "0.7.9"
}


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.1.1'
    compile 'org.jacoco:org.jacoco.core:0.7.9'
    compile 'com.android.support.constraint:constraint-layout:+'
}

def coverageSourceDirs = [
        '../app/src/main/java'
]

task jacocoTestReport(type: JacocoReport) {
    group = "Reporting"
    description = "Generate Jacoco coverage reports after running tests."
    reports {
        xml.enabled = true
        html.enabled = true
    }
    classDirectories = fileTree(
            dir: './build/intermediates/classes/debug',
            excludes: ['**/R*.class',
                       '**/*$InjectAdapter.class',
                       '**/*$ModuleAdapter.class',
                       '**/*$ViewInjector*.class'
            ])
    sourceDirectories = files(coverageSourceDirs)
    executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")

    doFirst {
        new File("$buildDir/intermediates/classes/").eachFileRecurse { file ->
            if (file.name.contains('$$')) {
                file.renameTo(file.path.replace('$$', '$'))
            }
        }
    }
}

写入ec文件

自定义一个JacocoUtils类,可以根据反射拿到方法、类的执行代码,写入到.ec文件

代码语言:javascript
复制
  public static void generateEcFile(boolean isNew) {
//        String DEFAULT_COVERAGE_FILE_PATH = NLog.getContext().getFilesDir().getPath().toString() + "/coverage.ec";
        Log.d(TAG, "生成覆盖率文件: " + DEFAULT_COVERAGE_FILE_PATH);
        OutputStream out = null;
        File mCoverageFilePath = new File(DEFAULT_COVERAGE_FILE_PATH);
        try {
            if (isNew && mCoverageFilePath.exists()) {
                Log.d(TAG, "JacocoUtils_generateEcFile: 清除旧的ec文件");
                mCoverageFilePath.delete();
            }
            if (!mCoverageFilePath.exists()) {
                mCoverageFilePath.createNewFile();
            }
            out = new FileOutputStream(mCoverageFilePath.getPath(), true);

            Object agent = Class.forName("org.jacoco.agent.rt.RT")
                    .getMethod("getAgent")
                    .invoke(null);

            out.write((byte[]) agent.getClass().getMethod("getExecutionData", boolean.class)
                    .invoke(agent, false));
            Log.d(TAG,"写入" + DEFAULT_COVERAGE_FILE_PATH + "完成!" );
        } catch (Exception e) {
            Log.e(TAG, "generateEcFile: " + e.getMessage());
            Log.e(TAG,e.toString());
        } finally {
            if (out == null)
                return;
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();

            }
        }
    }

使用Application生成ec

继承Application类,重写onTrimMemory方法,系统会根据不同的内存状态来回调

代码语言:javascript
复制
系统提供的回调有:
Application.onTrimMemory()
Activity.onTrimMemory()
Fragement.OnTrimMemory()
Service.onTrimMemory()
ContentProvider.OnTrimMemory()
OnTrimMemory的参数是一个int数值,代表不同的内存状态:
TRIM_MEMORY_COMPLETE:内存不足,并且该进程在后台进程列表最后一个,马上就要被清理
TRIM_MEMORY_MODERATE:内存不足,并且该进程在后台进程列表的中部。
TRIM_MEMORY_BACKGROUND:内存不足,并且该进程是后台进程。
TRIM_MEMORY_UI_HIDDEN:内存不足,并且该进程的UI已经不可见了。 

可以根据level == TRIM_MEMORY_UI_HIDDEN来确定app已经至于后台,此时调用generateEcFile方法.

代码语言:javascript
复制
    //判断是否是后台
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        if (level == TRIM_MEMORY_UI_HIDDEN) {
            isBackground = true;
            notifyBackground();
        }
    }

    private void notifyBackground() {
        // This is where you can notify listeners, handle session tracking, etc
        Log.d(TAG, "切到后台");
        JacocoUtils.generateEcFile(true);
    }

操作步骤

给予app读写sdcard权限

因为我的是简单的demo代码,启动没有弹窗询问读写sdcard权限, Android6.0以后是动态获取权限了,所以需要手动去设置中把sdcard权限打开,实际项目应该不存在手动打开的步骤.

手工执行

安装app->操作app->app放置后台->分析ec文件.

自动化执行

可以结合monkey和UI自动化,我简单写了个shell脚本.从编译app、启动app、app至于后台、自动展示jacoco报告

代码语言:javascript
复制
#!/usr/bin/env bash
#当前在环境为Project/app目录

apk_path=`pwd`/app/build/outputs/apk/app-debug.apk
report_path=`pwd`/reporter/index.html

echo "打包app"
gradle assembleDebug
adb uninstall com.weex.jasso
echo "安装app"
adb install ${apk_path}
echo "启动app"
adb shell am start -W -n com.weex.jasso/.Test1Activity -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000
sleep 2
echo "关闭app"
adb shell am force-stop com.weex.jasso

rm -rf `pwd`/new.ec
rm -rf `pwd`/report
adb pull /sdcard/jacoco/coverage.ec `pwd`/new.ec

macaca coverage -r java -f `pwd`/new.ec -c `pwd`/app/build/intermediates/classes/debug -s `pwd`/app/src/main/java --html `pwd`/reporter
echo "jacoco报告地址:"${report_path}
open -a "/Applications/Safari.app" ${report_path}

效果

macaca coverage生产报告

使用gradle的jacocoTestReport也可以生产报告,也是大多人使用的方式,本文就不做介绍了,主要介绍使用macaca coverage方法.

macaca coverage可以生成jacoco报告,不仅可以生成Android项目,也可以生产iOS、web项目.具体使用请查看https://macacajs.github.io/zh/coverage.

代码语言:javascript
复制
安装macaca-coverage命令:

npm i macaca-cli -g
macaca coverage -h
npm i macaca-coverage --save-dev
代码语言:javascript
复制
macaca coverage命令:
macaca coverage -r java -f `pwd`/new.ec -c `pwd`/app/build/intermediates/classes/debug -s `pwd`/app/src/main/java --html `pwd`/reporter

项目代码

代码语言:javascript
复制
https://github.com/xinxi1990/jacocodemo.git

在项目根目录有个jacaco_test.sh,可以完成自动化测试.

意义

1、都一套自己的测试思维,会有测试边界或者测试未覆盖的区域.

2、通过白盒方式嵌入式测试代码逻辑,补全测试用例.

3、度量测试投入度,用数据统计说话.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 测试加 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 代码配置
    • build.gradle
      • 写入ec文件
      • 使用Application生成ec
      • 操作步骤
        • 给予app读写sdcard权限
          • 手工执行
            • 自动化执行
            • 效果
            • macaca coverage生产报告
            • 项目代码
            • 意义
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档