第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,则覆盖率测试不需要关注它们。这些模块的功能由第三方保证,如果有问题只需要反馈给他们即可。

相关推荐
season_zhu6 分钟前
iOS开发:关于日志框架
ios·架构·swift
Digitally4 小时前
如何在电脑上轻松访问 iPhone 文件
ios·电脑·iphone
安和昂4 小时前
【iOS】YYModel源码解析
ios
pop_xiaoli4 小时前
UI学习—cell的复用和自定义cell
学习·ui·ios
大熊猫侯佩4 小时前
SwiftUI 中如何花样玩转 SF Symbols 符号动画和过渡特效
swiftui·swift·apple
大熊猫侯佩5 小时前
SwiftData 共享数据库在 App 中的改变无法被 Widgets 感知的原因和解决
swiftui·swift·apple
大熊猫侯佩5 小时前
使用令牌(Token)进一步优化 SwiftData 2.0 中历史记录追踪(History Trace)的使用
数据库·swift·apple
大熊猫侯佩5 小时前
SwiftUI 在 iOS 18 中的 ForEach 点击手势逻辑发生改变的解决
swiftui·swift·apple
Daniel_Coder6 小时前
Xcode 16.4 + iOS 18 系统运行时崩溃:___cxa_current_primary_exception 符号丢失的原因与解决方案
ios·xcode·ios 18·dyld·libc++abi
烈焰晴天9 小时前
使用ReactNative加载Svga动画支持三端【Android/IOS/Harmony】
android·react native·ios