iOS (Object-C) 非单元测试状态下代码覆盖率获取尝鲜

Posted pengyuan_D

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS (Object-C) 非单元测试状态下代码覆盖率获取尝鲜相关的知识,希望对你有一定的参考价值。

最近开始要调研精准测试,代码覆盖率是其中一个十分重要的部分,因此参考网上的流程来试做一下。过程中发现由于 Xcode 8 有一些变化,网上的相关文章都没有对应更新,所以发文记录下。

目标

在操作应用过程中,通过一个特定操作可获取到从应用启动到此操作前所有操作的覆盖率数据。

需要用到的工具

  • XcodeCoverage
  • Xcode 8.1(为了支持 ios 10.1,亲测可在最新的 iOS 10.1.1 中成功获得覆盖率)

配置步骤

项目加入 XcodeCoverage

只用过 pod 的方式,也建议使用这个方式安装,比较快捷。

  1. 在 Podfile 中加入 pod 'XcodeCoverage', '~>1.0'
  2. 运行 pod install
  3. 在需要获取覆盖率的 target 中加入 Run Script 的步骤,内容为 Pods/XcodeCoverage/exportenv.sh

  • 官方最新的 1.3 貌似不兼容 Xcode 8 ,需要做一些调整。
  1. 下载最新的官方代码:git clone https://github.com/jonreid/XcodeCoverage.git
  2. 拷贝官方的 lcov-1.12/bin 内所有文件到项目所在的 Pod/XcodeCoverage/lcov-1.12/bin 中,同名文件直接覆盖

项目配置添加获取代码覆盖率的相关配置

一般情况下,我们只在 Debug 包中获取代码覆盖率,因此只改动 Debug 的配置。需要改动的地方有两个,以下直接贴图:

 

 

 

 

项目源码中添加生成覆盖率的相关代码

在 AppDelegate.m 中添加如下代码(代码参考自 vigossjjj/CodeCoverage4iOS 项目):

- (void)applicationDidEnterBackground:(UIApplication *)application

#if !TARGET_IPHONE_SIMULATOR
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    setenv("GCOV_PREFIX", [documentsDirectory cStringUsingEncoding:NSUTF8StringEncoding], 1);
    setenv("GCOV_PREFIX_STRIP", "13", 1);
#endif
    
    extern void __gcov_flush(void);
    __gcov_flush();
    
    [[BHModuleManager sharedManager] triggerEvent:BHMDidEnterBackgroundEvent];

这部分代码触发点是点击 home 键应用进入后台时。其中 #if !TARGET_IPHONE_SIMULATOR 中包含的部分会改写环境变量,让生成的覆盖率文件( .gcda 文件)放在应用的沙箱中。否则默认会保存在对应 mac 电脑的路径,但由于应用没有写入 mac 电脑路径的权限,因而一直无法生成。

获取覆盖率

获取模拟器运行覆盖率

  1. 在 xcode 中 build ,然后 run 
  2. 在应用中做出操作
  3. 点击 home 键,应用进入后台,同时应用自动生成对应覆盖率文件
  4. 进入 项目目录/Pod/XcodeCoverage,运行命令 ./getcov --show ,即可自动生成覆盖率报告。

获取真机运行覆盖率

  1. 在 xcode 中 build ,然后 run 
  2. 在应用中做出操作
  3. 点击 home 键,应用进入后台,同时应用自动生成对应覆盖率文件
  4. 打开 Xcode->window->Devices ,选择运行应用的真机
  5. 在 Installed Apps 部分选择运行的应用,然后点击底部的齿轮按钮,选择 'Download Container'
  6. 把生成的 xcappdata 文件保存下来,然后在 finder 中打开
  7. 对 xcappdata 文件右键->显示包内容(show package content),然后打开 AppData/Documents/arm64/,拷贝里面的所有 .gcda 文件
  8. 进入 项目目录/Pod/XcodeCoverage,打开 env.sh,找到 OBJECT_FILE_DIR_normal 及 CURRENT_ARCH 。
  9. 打开应用编辑结果存储的目录,对应的路径为 <OBJECT_FILE_DIR_normal>/<CURRENT_ARCH>,其中 OBJECT_FILE_DIR_normal 及 CURRENT_ARCH 是上一步找到的值。(大于小于号不需要保留)
  10. 把第7步的 .gcda 文件全部拷贝到第9步打开的目录
  11. 回到 项目目录/Pod/XcodeCoverage ,运行命令 ./getcov --show ,即可自动生成覆盖率报告。

报告样式:

 

 

主要的坑就在真机运行和模拟器运行时目录的区别。 真机运行时,真机上应用无法写入 mac 上的路径,因此 .gcda 文件只能放在手机沙箱,另外取出。模拟器无此问题(模拟器有写入 mac 路径的权限)

后续

覆盖率拿到了,但过程仍然不够自动化,还需要解决覆盖率数据自动回传、通过按钮触发 dump 等问题才能达到最基本的要求。后续再往这个方面继续探究。

参考文档

https://github.com/jonreid/XcodeCoverage/blob/master/README.md

https://github.com/jonreid/XcodeCoverage/issues/48

https://github.com/vigossjjj/CodeCoverage4iOS/blob/master/README.md

以上是关于iOS (Object-C) 非单元测试状态下代码覆盖率获取尝鲜的主要内容,如果未能解决你的问题,请参考以下文章

Object-C与Swift混合开发

是否可以为 iOS 编写应用程序并将 object-c 代码移动到 Android 中?

[Object-C语言随笔之一]Mac os 下搭建iOS开发环境

Object-C编程之道 iOS设计模式解析--原型模式

Object-C与Swift混合开发

iOS 单元测试:如何对 firstResponderStatus 进行单元测试