第2.5节 iOS 覆盖率数据的采集

iOS系统不像Android系统这么灵活,有众多工具可以支持我们的测试,不过在覆盖率方面,也是有一定的工具的,但无法做二次开发。目前iOS主流的开发语言有Object C和Swift,下面针对这两个语系做不同的覆盖率采集分析。

2.5.1 Object C项目

Object C开发的iOS项目,使用提XcodeCoverage工具来采集覆盖率数据的,覆盖率数据是针对每个类有一个对应的gcda文件,这个文件就是覆盖率数据文件,如同Android的覆盖率数据ec文件。

一,iOS XcodeCoversage插桩

1,从网上下载Demo
下载地址: https://github.com/shabake/GHDropMenuDemo

2,编辑Podfile文件, 添加XcodeCoverage库
在项目的根目录下创建Podfile文件,添加如下内容:
platform :ios, '10.0' target 'GHDropMenuDemo' do pod 'XcodeCoverage', '~>1.0' end
执行命令pod install安装依赖库。
3,Xcode工程配置
(1) 使用Xcode打开项目,Targes -> 选择你的APP -> Build Settings -> 搜索Preprocessor Macros -> 展开在Debug一栏加入NT_COVERAGE=1

注意这里我们都只修改Debug模式下的属性, 避免影响线上版本的打包发布
(2) 同样在Build Settings中将以下3项的Debug模式改为Yes

  • Generate Debug Symbols 配置成YES
  • Generate Legacy Test Coverage Files 配置成YES
  • Instrument Program Flow 配置成YES



    (3)Build Phase中 -> New Run Script Phase -> Run Scrip中添加Pods/XcodeCoverage/exportenv.sh


    这里有个注意的地方, 如果原本项目中已经有一个run script也还是新建一个
    (4) AppDelegate.m中applicationDidEnterBackground方法添加以下代码:

    当被测试应用进入后台时,生成覆盖率数据文件主要调用函数 __gcov_flush();

二,编译测试

1,设置应用的证书,将手机连接到电脑,安装Debug包。

2,执行手工测试用例或是自动化测试用例
注意每次完成测试后先按Home键退到后台, 等几秒让APP产生覆盖率日志不要直接杀掉APP进程

三,提取覆盖率数据

如果是在模拟器上运行测试可以跳过此步

  1. 打开Xcode -> window -> Devices and Simulaters, 选择运行测试的真机
  2. 在Installed Apps中选择测试的应用,然后点击底部的齿轮按钮选择Download Container
  3. 会得到一个xxxx.xcappdata文件
  4. 右键点击xcappdata文件 -> 显示包内容, 进入AppData/Documents/arm64/, 拷贝里面的所有.gcda文件

    这里的gcda文件就是本次测试所有覆盖情况的覆盖率数据文件。

2.5.2 Swift项目

在 Swift 发展的早期,业内曾经有 SwiftCov 这样的工具可以用来生成覆盖率数据,但是随着 Swift2 原生支持了覆盖率信息,目前 Swift 的覆盖率事实上有且只有一套官方的方案,是基于 LLVM 实现的。基于官方方案的另一个好处是,配套工具相对比较成熟,比如可以生成网页,能够精确展示每行代码的执行情况,并且能够支持范型特化等多种复杂场景的统计。

一,Swift覆盖率配置

为了方便总结,我们从网上下载一个示例Demo: https://github.com/ChinaArJun/shopping-cart-Demo

项目非常很简单,直接进行编译就可以了。
1,配置 Other Swift Flags
在项目的"Build Settings"--->"Other Swift Flags"--->"Debug", 双击后面的配置项

将这两个配置添加进去:" -profile-generate 和 -profile-coverage-mapping ",注意不要改变原来的项目配置

2,设置覆盖率作用于所有的项目
"Product"--->"scheme"---->"edit scheme....",在打开的对话框中,勾选"Gather coverage for all targets".

3,添加LLVM相关定义
在swift项目中添加头文件,如:InstrProfiling.h,内容如下

objectivec 复制代码
#ifndef InstrProfiling_h
#define InstrProfiling_h

#ifndef PROFILE_INSTRPROFILING_H_
#define PROFILE_INSTRPROFILING_H_
int __llvm_profile_runtime = 0;
void __llvm_profile_initialize_file(void);
const char *__llvm_profile_get_filename();
void __llvm_profile_set_filename(const char *);
int __llvm_profile_write_file();
int __llvm_profile_register_write_file_atexit(void);
const char *__llvm_profile_get_path_prefix();
#endif /* PROFILE_INSTRPROFILING_H_ */


#endif /* InstrProfiling_h */

创建一个 module.modulemap 文件并将所有内容导出为一个模块。

objectivec 复制代码
module InstrProfiling { header "InstrProfiling.h" export * }

4,在Swift项目中调用OC内容
事实上我们不能直接创建 module.modulemap ,首先创建一个 module.c 文件然后重命名为 module.modulemap ,它还可以帮助我创建一个 ShoppingCart-Bridging-Header 文件。
(1) 创建module.c文件

(2)创建Bridging Header文件

本项目中,我们没有引用第三方的OC类,此文件中可以不写内容。如果有引用,在此文件中添加对第三类的头文件的引用。Swift文件中就可以使用oc的类及函数。
(3)设置Badging Header文件
找到Build Setting配置下的"Object-C Bridging Header"项,看后面的值是没有刚刚创建的文件,如:

如果没有,双击打开一个弹层,将左侧的Bridging文件拖过来,自动填写相应的路径。
5, 在项目中添加生成覆盖率的操作
通常我们会在应用进入后台的时候,生成覆盖率数据,所以在AppDelegate.swift下的applicationDidEnterBackground函数中,添加如下操作:

objectivec 复制代码
let name = "test.profraw"
        let fileManager = FileManager.default                
        do {
            let documentDirectory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
            let filePath: NSString = documentDirectory.appendingPathComponent(name).path as NSString
            __llvm_profile_set_filename(filePath.utf8String)
            __llvm_profile_write_file()
            print("文件路径:"+(filePath as String))
        } catch {
            print(error)
        }

此段代码,会在应用进入到后台时,在Documents目录下生成覆盖率数据文件,test.profraw.

二,执行测试并获取覆盖率数据

经过上面的配置后,再配置一下证书,就可以将应用打包并安装到手机上。然后执行你需要的测试用例即可,然后将应用置入后台一会儿。
1,导出覆盖率数据:选择Xcode的"windows"---->"Devices and Simulators "在打开的对应框中选择手机设备;

2,选择应用,导出应用数据
选择『shoppingCart』---"Download container" 下载应用数据。

3,打开container,查找覆盖率数据
右击文件选择『显示包内容』--->AppData-->Doucuments--->就可以找到覆盖率数据文件。
将数据文件拷到指定的文件夹,就可以生成报告。

2.5.3 总结

通过上面对Object C和Swift项目的配置,在测试过程中就能采集到测试执行对应的覆盖率数据。注意:上面的配置是针对单独应用的,如果您的应用引入了多个模块,也需要对不同的模块进行处理。
1,如果模块源码和项目源码在一起,就需要对模块进行配置,可采取如下方案,在Podfile中添加如下代码:

objectivec 复制代码
#覆盖率测试需要采集数据的module
ckmodules=Array['moduellist']

post_install do |installer|
  # 修改Pods中某一个模块的配置文件,好采集代码覆盖率,需要源码!
  installer.pods_project.targets.each do |target|
    ckmodules.each do |ckmodule|
      if ckmodule == target.name
          target.build_configurations.each do |config|
            config.build_settings['OTHER_CFLAGS'] = '$(inherited) -fprofile-instr-generate -fcoverage-mapping'
            config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -profile-generate -profile-coverage-mapping'
            config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -fprofile-instr-generate' 
          end
      end
    end
  end
end

2,如果模块源码和项目不在一起,就是第三方的模块,SDK,则覆盖率测试不需要关注它们。这些模块的功能由第三方保证,如果有问题只需要反馈给他们即可。

相关推荐
卢叁3 分钟前
Swift int转String的诡异bug
ios
90后的晨仔15 小时前
iOS 中的 RunLoop 详解
前端·ios
比特鹰17 小时前
手把手教你用Flutter打包内测版本的IOS App
前端·ios
xinxiyinhe1 天前
Swift语音助手(苹果生态系统的核心编程语言)
人工智能·swift
MingDong5231 天前
AirPods 4(主动降噪版本) 和 老版的AirPods Pro2对比
ios
二流小码农1 天前
鸿蒙开发:Canvas绘制之画笔对象Brush
android·ios·harmonyos
二流小码农1 天前
鸿蒙开发:事件订阅EventHub
android·ios·harmonyos
二流小码农2 天前
鸿蒙开发:Canvas绘制之画笔对象Pen
android·ios·harmonyos
90后的晨仔2 天前
Swift基础知识(三)
ios
90后的晨仔2 天前
Swift基础知识(二)
ios