iOS由于其系统的特殊性,很多操作需要在Mac电脑上完成,所以也就无法部署到容器上。于是将iOS Agent开发成单独的服务,由Django开发,对外提供http请求接口,部署到Mac机器上以响应精准测试平台的请求。
6.3.1 Agent整体架构介绍
1,Agent功能架构图

2,功能模块介绍
(1)OC项目模块
针对 Object-C项目的生成覆盖率相关的操作,包括Clone项目,构建项目(需要构建后的Class文件),上传覆盖率文件(此文件为打包后的zip文件),XcodeCoverage生成覆盖率报告,以及解析覆盖率报告数据(取行覆盖率相关数据),下载覆盖率报告,以便精准测试平台展示。
- 构建项目生成报告类iOSCovOperations:
python
# coding=utf-8
import os,shutil
import zipfile
from iOSOCAndSwiftAgent.UtilsOperation.const import DEBUG_SERVICE
class iOSCovOperations(object):
"""
iOS覆盖率相关操作
"""
def getGcnoFilePath(self,propath):
"""获取项目构建后的gcno文件路径"""
envfilepath=propath+"Pods/XcodeCoverage/env.sh";
gcnopath=""
rfile=open(envfilepath)
line=rfile.readline()
while line:
if line.find("OBJECT_FILE_DIR_normal")>-1:
gcnopath=line[line.index("=")+2:line.rindex("\"")]
break
line=rfile.readline()
gcnopath=gcnopath+"/arm64"
return gcnopath
def copygcnofile(self,propath):
"""
拷贝构建后的文件
:param propath:
:return:
"""
# 4,拷贝构建后的代码到指定路径
gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
if os.path.exists(gcnopath):
shutil.rmtree(gcnopath)
shutil.copytree(self.getGcnoFilePath(propath),gcnopath)
def buildPorject(self,propath):
"""构建iOS项目"""
curpath = os.getcwd();
scriptpath=""
print("当前目录是:"+curpath)
if DEBUG_SERVICE.find("Agent")>-1:
#写死Agent上的路径
scriptpath="/Users/****/ScriptFiles/"
else:
#本机debug
scriptpath="/Users/*****/ScriptFiles/"
os.chdir(propath)
# 1,pod安装
os.system("pod install")
# 2,拷贝构建脚本
os.system("cp "+scriptpath+"EnterpriseExportOptionsPlist.plist "+propath+"EnterpriseExportOptionsPlist.plist")
os.system("cp "+scriptpath+"xcodebuild.sh "+propath+"xcodebuild.sh")
os.system("chmod 777 "+propath+"xcodebuild.sh")
# 获取项目名称
proname=""
for f in os.listdir(propath):
print("file name:"+f)
if f.find("xcworkspace")>-1:
proname=f[0:f.index(".")]
break
#3,构建项目
if len(proname)>0:
os.system(propath+"xcodebuild.sh "+proname+" &")
else:
print("项目中没有项目文件,请检测项目内容是否有遗漏!")
# # 4,拷贝构建后的代码到指定路径
# gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
# if os.path.exists(gcnopath):
# shutil.rmtree(gcnopath)
# shutil.copytree(self.getGcnoFilePath(propath),gcnopath)
#5,切换回当前目录
os.chdir(curpath)
return True
def createiOSCovReport(self,propath,covdatapath):
"""根据覆盖率数据文件,生成覆盖率执行"""
#1,拼出gcno文件路径
gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
#2,拷贝构建后的文件到覆盖率文件中
for fileName in os.listdir(gcnopath):
srcFile = os.path.join(gcnopath,fileName)
tarFile = os.path.join(covdatapath,fileName)
shutil.copyfile(srcFile,tarFile)
#3,覆盖率报告路径
covreppath=propath+"Pods/XcodeCoverage/tempreports/"+covdatapath[covdatapath.rindex("/")+1:len(covdatapath)]
if not os.path.exists(covreppath):
os.makedirs(covreppath)
#4,重写env.sh文件内容
envfile=propath+"Pods/XcodeCoverage/env.sh"
os.remove(envfile)
wrfile=open(envfile,"w+")
#写入BUILT_PRODUCTS_DIR
wrfile.write("export BUILT_PRODUCTS_DIR=\""+covreppath+"\"\t\n");
#写入export CURRENT_ARCH=""
wrfile.write("export CURRENT_ARCH=\"\"\t\n");
#写入OBJECT_FILE_DIR_normal
wrfile.write("export OBJECT_FILE_DIR_normal=\""+covdatapath+"\"\t\n");
#写入OBJROOT
wrfile.write("export OBJROOT=\"\"\t\n");
#写入SRCROOT
wrfile.write("export SRCROOT=\""+propath+"\"\t\n");
wrfile.close()
#5,执行生成报告命令
getcovcmd=propath+"Pods/XcodeCoverage/getcov"
os.system(getcovcmd)
return covreppath
def createXcodeCoverageReport(self,propath,covdatapath):
"""根据覆盖率数据,合并报告生成最终的报告"""
gedatapath = propath + "Pods/XcodeCoverage/coverage"
if not os.path.exists(gedatapath):
os.makedirs(gedatapath)
xcreppath = propath + "Pods/XcodeCoverage/report"
if not os.path.exists(xcreppath):
os.makedirs(xcreppath)
#遍历覆盖率数据文件夹,分别生成报告
count=0
for file in os.listdir(covdatapath):
if file.find("arm")>-1:
tempcovpath=covdatapath+"/"+file
print("数据文件:"+tempcovpath)
temprep=self.createiOSCovReport(propath,tempcovpath)
#拷贝生成的Coverage.info文件
os.system("cp "+temprep+"/lcov/Coverage.info "+gedatapath+"/Coverage"+str(count)+".info")
count=count+1
# 生成整体覆盖率的报告
mercmd=propath+"Pods/XcodeCoverage/mergecov"
curpath = os.getcwd();
if DEBUG_SERVICE.find("Agent")>-1:
#写死Agent上的路径
scriptpath="/Users/****/ScriptFiles/"
else:
#本机debug
scriptpath="/Users/*****/ScriptFiles/"
os.system("cp "+scriptpath+"mergecov "+mercmd)
os.system("chmod 777 "+mercmd)
os.system(mercmd)
# 将生成的测试报告打包
output_filename=propath+"report.zip"
zipf = zipfile.ZipFile(output_filename, 'w')
pre_len = len(os.path.dirname(xcreppath))
for parent, dirnames, filenames in os.walk(xcreppath):
for filename in filenames:
pathfile = os.path.join(parent, filename)
arcname = pathfile[pre_len:].strip(os.path.sep)
zipf.write(pathfile, arcname)
zipf.close()
return xcreppath
def getCovData(self,reppath):
"""
获取覆盖率报告中的数据
:param reppath:
:return:
"""
file=open(reppath,"r")
line=file.readline()
covlines=""
totallines=""
covlinerate=""
covfuns=""
totalfuns=""
covfunrate=""
while line:
line=file.readline()
if line.find("headerCovTableEntry")>-1:
if len(covlines)==0:
covlines=line[line.index(">")+1:line.rindex("<")]
continue
if len(covlines)>0 and len(totallines)==0:
totallines=line[line.index(">")+1:line.rindex("<")]
continue
if line.find("%")>-1 and len(covlinerate)==0:
covlinerate=line[line.index(">")+1:line.rindex("<")]
continue
if len(covfuns)==0:
covfuns=line[line.index(">")+1:line.rindex("<")]
continue
if len(covfuns)>0 and len(totalfuns)==0:
totalfuns=line[line.index(">")+1:line.rindex("<")]
continue
if line.find("%")>-1 and len(covfunrate)==0:
covfunrate=line[line.index(">")+1:line.rindex("<")]
break
repdata={"totalines":totallines,"covlines":covlines,"covlinerate":covlinerate,"totalfuns":totalfuns,"covfuns":covfuns,"covfunrate":covfunrate}
return repdata
if __name__ == '__main__':
iosopr=iOSCovOperations()
propath="/Users/****/ghdropmenudemo/"
covdatapath="/Users/****/ghdropmenudemo/Pods/XcodeCoverage/tempcovdata"
iosopr.getCovData(propath+"Pods/XcodeCoverage/report/index.html")
此方案主要在构建项目上比较耗时,可以采取在公司打包平台打包后上传构建文件,以节省时间;同时上传的覆盖率数据文件也较大,由于公司的项目是Swift的,这个模块也没有再继续优化,使用测试Demo验证,相关功能没有问题