当前位置: 首页 > 科技观察

基于源码的Swift代码覆盖率的逐步实现

时间:2023-03-16 12:31:49 科技观察

介绍最近在研究自己公司项目基于Swift的代码覆盖率检测方案的解决方案,经过一番努力,找到了最佳实践。在这篇简短的文章中,我将向您介绍:如何通过命令行生成*.profraw文件并测量代码覆盖率如何在SwiftApp项目中调用C/C++方法如何在XcodeRatio中测量完整SwiftApp项目的代码覆盖率命令行练习在我们衡量完整的App项目的代码覆盖率之前,我们需要创建一个简单的Swift源代码文件,并使用命令行生成一个*.profraw文件,这样我们就可以学习如何生成覆盖率配置文件基本工作流程。创建一个Swift文件并包含以下代码:test()print("hello")functest(){print("test")}funcadd(_x:Double,_y:Double)->Double{returnx+y}test()在终端中运行以下命令:swiftc-profile-generate-profile-coverage-mapping你好。通过swiftc传递给编译器的选项-profile-generate和-profile-coverage-mapping将在编译源代码时启用覆盖功能。基于源的代码覆盖函数直接对AST和预处理器信息进行操作。然后运行输出二进制文件:./hello运行后,在当前目录下执行ls,我们会看到这里生成了一个新的文件,名称为default.profraw。该文件由llvm生成,为了测量代码覆盖率,我们必须使用另一个工具llvm-profdata来组合多个原始配置文件并同时索引它们。xcrunllvm-profdatamerge-sparsedefault.profraw-ohello.profdata在终端中运行上面的命令行,我们会得到一个名为hello.profdata的新文件,它可以显示我们想要的覆盖率报告。我们可以使用llvm-cov来显示或生成JSON报告。xcrunllvm-covshow./hello-instr-profile=hello.profdataxcrunllvm-covexport./hello-instr-profile=hello.profdata现在我们已经了解了生成快速代码覆盖率报告的基本工作流程。看起来Swift基于源码的代码覆盖并没有那么难。但是,在Xcode中配置一个完整的SwiftApp项目,与命令行是有很大区别的。那么让我们继续阅读吧!在Xcode中测量SwiftApp项目的代码覆盖率创建一个Swift项目选择SwiftCovApp目标->构建设置->Swift编译器—自定义标志。在OtherSwiftFlags中添加-profile-generate和-profile-coverage-mapping选项:如果我们现在尝试编译,我们会得到以下错误报告:Enablecodecoverage:enablecodecoverage后再次运行,项目将构建成功。我们了解到,当程序退出时,编译器会将原始配置文件写入到LLVM_PROFILE_FILE环境变量指定的路径中。所以我们应该杀掉Application进程来执行*.profraw文件。但是,当我们结束应用程序时,它会在控制台中抛出错误:Xcode中的默认环境路径为空,尽管我在BuildSettings中设置了相同的配置。要解决这个问题,我们必须新建一个头文件,声明一些llvmCapi函数供Swift调用。在Swift中调用C/C++方法Swift是一种基于C/C++的强大语言,可以直接调用C/C++方法。然而,在我们调用llvmC/C++api之前,我们必须将我们需要的方法导出为一个模块。首先,创建一个头文件:然后,将以下代码复制粘贴到该文件中:#ifndefPROFILE_INSTRPROFILING_H_#definePROFILE_INSTRPROFILING_H_int__llvm_profile_runtime=0;void__llvm_profile_initialize_file(void);constchar*__llvm_profile_get_filename();void__llvcharm_profile_st(constm_profile_profileint__llvfile_profile__llvfile_st(constm_profile_profile__llvfile_profile));int__llvm_profile_register_write_file_atexit(void);constchar*__llvm_profile_get_path_prefix();#endif/*PROFILE_INSTRPROFILING_H_*/创建一个module.modulemap文件并将所有内容导出为模块。////module.modulemap////yao创建于2020/10/15.//moduleInstrProfiling{header"InstrProfiling.h"export*}其实我们不能直接创建module.modulemap,先创建一个module.c文件并将其重命名为module.modulemap,它还帮助我创建了一个SwiftCovApp-Bridging-Header文件。构建项目,然后,我们可以在Swift代码中调用llvmapi。importUIKitimportInstrProfilingclassViewController:UIViewController{overridefuncviewDidLoad(){super.viewDidLoad()//在加载视图后做任何额外的设置。print("文件路径前缀:\(String(cString:__llvm_profile_get_path_prefix()))")print("文件名:\(String(cString:__llvm_profile_get_filename()))")letname="test.profraw"letfileManager=FileManager.defaultdo{letdocumentDirectory=tryfileManager.url(for:.documentDirectory,in:.userDomainMask,appropriateFor:nil,create:false)letfilePath:NSString=documentDirectory.appendingPathComponent(name).pathasNSString__llvm_profile_set_filename(filePath.utf8String)print("FileName:\(String(cString:__llvm_profile_get_filename()))")__llvm_profile_write_file()}catch{print(error)}}}构建并启动App,我们将在控制台中看到原始配置文件路径。最后,我们有了所需的原始配置文件!