1. gtci.py
# -*- coding: utf-8 -*-
import sys,os
from testcaseinfo import TestCaseInfo
from runlistinfo import RunListInfo
if __name__ == '__main__':
reload(sys)
if (len(sys.argv) < 2):
print 'python gtci.py module ***'
exit()
#print sys.argv[1], sys.argv[2], sys.argv[3]
module = sys.argv[1]
if module == '-c':
if (4 >= len(sys.argv)):
print 'python gtci.py dirctory module author'
print 'python gtci.py dirctory module bat'
exit()
if 0 == os.path.exists(sys.argv[2]):
print 'the path does not exist, pls check it! ^_^\n'
exit()
if os.path.isfile(sys.argv[2]):
print 'the path is file, pls use dirctory! ^_^\n'
exit()
sys.setdefaultencoding('utf-8')
TestCaseInfo().GetTestCaseList(sys.argv[2], sys.argv[3], sys.argv[4])
if module == '-r':
if (len(sys.argv) < 3):
print 'python gtci.py module path'
exit()
else :
path = sys.argv[2]
filepath = os.getcwd() + '/' + path
print filepath
RunListInfo().GetRunListInfo(filepath)
<pre name="code" class="python">import sys,os
from testcaseinfo import TestCaseInfo
from runlistinfo import RunListInfo
导入了两个python系统的模块和自定义的模块,自定义的模块后面再说,先来讲一下sys这个模块在这里的一个注意点。我们看到后面有这样一条代码:
reload(sys)
这时候为什么要动态加载sys模块呢,我们前面不是import过了吗?
原因:
sys.setdefaultencoding('utf-8')
我们看到这里调用setdefaultencoding去设置默认编码格式,而reload(sys)就是为了让这个方法可以被调用。
因为python解释器在启动的时候会调用site.py,在里面有这样一段代码:
# Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization. The test for presence is needed when
# this module is run as a script, because this code is executed twice.
if hasattr(sys, "setdefaultencoding"):
del sys.setdefaultencoding
这里看出解释器在启动的时候,实际上是把setdefaultencoding方法删除了,所以你想在你自己的程序中调用该方法,就必须重新加载sys模块。
下面根据两个不同的选项-c,-r分别调用两个不同的自定义模块
option: -c
TestCaseInfo().GetTestCaseList(sys.argv[2], sys.argv[3], sys.argv[4])
传入三个参数:参数一 测试用例所在文件路径;参数二 测试模块划分 例如Testing/Framework/Framework.app;参数三 模块负责人 nitibu
2. 接着看TestCaseInfo.py
def GetTestCaseList(self, testCasePath, module, author):
if (0 == cmp(author,'bat')) : #只获取运行列表
self.getrunlist = True
filetype = '.sh'
else :
filetype = '.lst'
listname = module[module.rfind('/')+1:] + filetype
f = open(listname,"w")
f.close()
#get testcases of classed added in dirs
dailyBuildCases = self.GetDailyBuildTestCaseList(testCasePath)
print dailyBuildCases
if os.path.exists(testCasePath + "/sources") :
self.GetTestCaseInfo(testCasePath, module, author, listname)
for root, dirs, files in os.walk(testCasePath, True, None, True):
for f in dirs:
path = os.path.join(root, f)
#only make a list with classes added in dirs
if path[path.rfind('/')+1:] in dailyBuildCases:
if os.path.exists(path + "/sources") :
self.GetTestCaseInfo(path, module, author, listname)
print "-----------------Testcase Count:",self.caseCount,"-----------------"
根据每个模块下面的dirs文件去判断是否需要生成对应类的测试用例运行列表
os.walk返回元组(dirpath, dirnames, filenames),分别表示--文件夹路径,子文件夹列表,文件夹下文件的列表(不是文件夹)
os.path.join合成子文件夹路径,然后再去调用GetTestCaseInfo去获取运行列表。
def GetTestCaseInfo(self, testCasePath, module, author, listname):
print "GetTestCaseInfo:",testCasePath
#if (0 == strcmp(author,'bat')) :
# self.getrunlist = True
CaseSets = []
item = (['00测试用例', '//测试用例: '],['01所属模块', '//所属模块: '],['02测试对象', '//测试对象: '],
['03函数原形', '//函数原形: '],['04参数说明', '//参数说明: '],['05运行环境', '//运行环境: '],
['06设计编码', '//设计编码: '],['07完成时间', '//完成时间: '],['08测试简述', '//测试简述: '],
['09测试类型', '//测试类型: '],['10优先级别', '//优先级别: '],['11输入文件', '//输入文件: '],
['12输出文件', '//输出文件: '],['13预期结果', '//预期结果: '],['14结果检查', '//结果检查: '],
['15运行方式', '//运行方式: '],['16补充说明', '//补充说明: '],['17测试路径', '//测试路径: '])
targetName,caseType = self.GetTestCaseName(testCasePath)
className = 'C' + targetName
if caseType == 'eco':
item[15][1] += 'am instrument -w -e class ' + className + '#'
else :
item[15][1] += targetName + ' '
strTime = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()));
item[7][1] += strTime
item[1][1] += module
item[6][1] += author
item[2][1] += testCasePath[testCasePath.rfind('/')+1:]
f = open(listname,"a")
for infile in glob.glob(testCasePath + "/*.cpp"):
testPath = infile[infile.find('/ElastosTest')+1:]
TestCaseInfo = dict(item)
caseStart = False
caseEnd = False
findCase = False
caseIndex = 00 #find case number
infoPre = ''
#if the encode is 'utf-8', chane it to 'GB2312'
# encodeType = self.GetEncodeType(infile)
# if "utf-8" == encodeType['encoding']:
# self.ChangeEncodeType(infile)
fileSources = open(infile)
try:
while True:
chunk = fileSources.readline()
if not chunk:
break
line = chunk.strip()
if 0 == line.find('/*') and -1 == line.find('*/'):
caseStart = True
findCase = False
if 0 == line.find('*/') and -1 == line.find('/*'):
caseEnd = True
findCase = True
caseStart = False
if findCase == True and -1 != line.find(className + '::Test') and -1 != line.find('('):
start = line.find('::Test')
end = line.find('(')
caseName = line[start+2:end]
findCase = False
caseStart = False
caseEnd = False
self.caseCount += 1
TestCaseInfo['00测试用例'] += str(self.caseCount)
TestCaseInfo['12输出文件'] += className + '_' + caseName + '.out'
TestCaseInfo['15运行方式'] += caseName + ' ' + targetName + '/Elastos.Droid.Test.CInstrumentationTestRunner'
TestCaseInfo['17测试路径'] += testPath
self.CheckTestCaseInfo(TestCaseInfo)
CaseSets.append(TestCaseInfo) #save caseinfo
TestCaseInfo = dict(item)
if findCase == True and -1 != line.find('CTest::') and -1 != line.find('('):
start = line.find('CTest::')
end = line.find('(')
caseIndex = line[start+11:end]
findCase = False
caseStart = False
caseEnd = False
self.caseCount += 1
TestCaseInfo['00测试用例'] += str(self.caseCount)
TestCaseInfo['12输出文件'] += targetName + '.out'
TestCaseInfo['15运行方式'] += str(caseIndex)
TestCaseInfo['17测试路径'] += testPath
self.CheckTestCaseInfo(TestCaseInfo)
CaseSets.append(TestCaseInfo) #save caseinfo
TestCaseInfo = dict(item)
if caseStart == True and 0 == line.find('* '):
pos = line.find("测试简述")
if -1 != pos:
TestCaseInfo['08测试简述'] += line[pos + 9:].strip()
infoPre = '08测试简述'
continue
pos = line.find("测试类型")
if -1 != pos:
TestCaseInfo['09测试类型'] += line[pos + 9:].strip()
continue
pos = line.find("优先级别")
if -1 != pos:
TestCaseInfo['10优先级别'] += line[pos + 9:].strip()
continue
pos = line.find("输入文件")
if -1 != pos:
TestCaseInfo['11输入文件'] += line[pos + 9:].strip()
continue
pos = line.find("预期结果")
if -1 != pos:
TestCaseInfo['13预期结果'] += line[pos + 9:].strip()
infoPre = '13预期结果'
continue
pos = line.find("结果检查")
if -1 != pos:
TestCaseInfo['14结果检查'] += line[pos + 9:].strip()
continue
pos = line.find("补充说明")
if -1 != pos:
TestCaseInfo['16补充说明'] += line[pos + 9:].strip()
infoPre = '16补充说明'
continue
#函数原型
#参数说明
finally:
fileSources.close()
for item in CaseSets:
if self.getrunlist :
f.write("%s" % item['15运行方式'][12:].strip()) #只获取运行列表
else :
for key in sorted(item.keys()):
f.write("%s\n" % item[key])
f.write('\n')
f.close()
item = (['00测试用例', '//测试用例: '],['01所属模块', '//所属模块: '],['02测试对象', '//测试对象: '],
['03函数原形', '//函数原形: '],['04参数说明', '//参数说明: '],['05运行环境', '//运行环境: '],
['06设计编码', '//设计编码: '],['07完成时间', '//完成时间: '],['08测试简述', '//测试简述: '],
['09测试类型', '//测试类型: '],['10优先级别', '//优先级别: '],['11输入文件', '//输入文件: '],
['12输出文件', '//输出文件: '],['13预期结果', '//预期结果: '],['14结果检查', '//结果检查: '],
['15运行方式', '//运行方式: '],['16补充说明', '//补充说明: '],['17测试路径', '//测试路径: '])
一堆中文,挺奇怪,很少见测试用例说明要求写中文的。建议过写英文,没人理会,后来才知道公司用的bug管理系统自己开发的,识别的就是中文,汗。。。
targetName,caseType = self.GetTestCaseName(testCasePath)
className = 'C' + targetName
if caseType == 'eco':
item[15][1] += 'am instrument -w -e class ' + className + '#'
else :
item[15][1] += targetName + ' '
strTime = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()));
item[7][1] += strTime
item[1][1] += module
item[6][1] += author
item[2][1] += testCasePath[testCasePath.rfind('/')+1:]
上面的代码获取了测试用例的运行方式、完成时间(没什么用,记录下当前时间吧)、所属模块、设计编码(这里就用来记录作者)、测试对象(代码所在路径)
上面的运行方式是必要的,其他暂时还用不到。
for infile in glob.glob(testCasePath + "/*.cpp"):
testPath = infile[infile.find('/ElastosTest')+1:]
TestCaseInfo = dict(item)
通过glob.glob获取指定路径下的所有cpp文件
记录某个测试文件cpp在测试目录ElastosTest下的path
根据item生成一个TestCaseInfo字典,这样就可以根据关键字去调用了
caseStart = False
caseEnd = False
findCase = False
caseIndex = 00 #find case number
infoPre = ''
用例说明模型
/*
检测到 /* 时表示检测到新用例,caseStart = True
检测到 */ 表示用例说明结束,caseEnd = True,这个时候下一行就是测试用例的执行体,设置findCase = True
ECode CActivityTest::TestGetCallingPackage()
{
String pkgName;
mActivity->GetCallingPackage(&pkgName);
AssertStringEquals(pkgName, String("FrameworkTestStub"));
return NOERROR;
}
找到测试用例后,每条测试用例都是Test开头,所以可以根据这个来获取测试用例方法名称。
if findCase == True and -1 != line.find(className + '::Test') and -1 != line.find('('):
start = line.find('::Test')
end = line.find('(')
caseName = line[start+2:end]
findCase = False
caseStart = False
caseEnd = False
self.caseCount += 1
TestCaseInfo['00测试用例'] += str(self.caseCount)
TestCaseInfo['12输出文件'] += className + '_' + caseName + '.out'
TestCaseInfo['15运行方式'] += caseName + ' ' + targetName + '/Elastos.Droid.Test.CInstrumentationTestRunner'
TestCaseInfo['17测试路径'] += testPath
self.CheckTestCaseInfo(TestCaseInfo)
CaseSets.append(TestCaseInfo) #save caseinfo
TestCaseInfo = dict(item)
设置测试用例编号、输出文件格式、运行方式、测试路径。
运行方式:am instrument -w -e class CComponentNameTest#TestConstructor ComponentNameTest/Elastos.Droid.Test.CInstrumentationTestRunner
然后检测下获取到的这些信息是否正确,由于编码不一样,会有获取的信息没法识别,这里判断的方式是计算一下获取到的信息的长度。
比如:'//优先级别: ' 一共有12个字节的长度,如果后面跟的是乱码,那就没法识别,信息长度就会小于等于12。如下:
def CheckTestCaseInfo(self, TestCaseInfo):
if len(TestCaseInfo['08测试简述']) <= 12:
print "warning: need case summary!!", " case : ",self.caseCount
if len(TestCaseInfo['09测试类型']) <= 12:
print "warning: need case type!!", " case : ",self.caseCount
if len(TestCaseInfo['10优先级别']) <= 12:
print "warning: need case priority!!", " case : ",self.caseCount
if len(TestCaseInfo['14结果检查']) <= 12:
print "warning: need case run mode!!", " case : ",self.caseCount
CaseSets.append(TestCaseInfo) #save caseinfo
TestCaseInfo = dict(item)
把获取到的信息追加到列表CaseSets中去,重新初始化TestCaseInfo,循环去获取测试用例信息。
最后把CaseSets中的信息都写到前面生成的列表文件中
for item in CaseSets:
if self.getrunlist :
f.write("%s" % item['15运行方式'][12:].strip()) #只获取运行列表
else :
for key in sorted(item.keys()):
f.write("%s\n" % item[key])
f.write('\n')
f.close()
最后获得的用例信息如下:
//测试用例: 1
//所属模块: Testing/Framework2/Framework.content
//测试对象: ComponentName
//函数原形:
//参数说明:
//运行环境:
//设计编码: nitibu
//完成时间: 2015-08-13 08:52:18
//测试简述: TestConstructor
//测试类型: 功能测试
//优先级别: P1
//输入文件:
//输出文件: CComponentNameTest_TestConstructor.out
//预期结果:
//结果检查: Dailybuild
//运行方式: am instrument -w -e class CComponentNameTest#TestConstructor ComponentNameTest/Elastos.Droid.Test.CInstrumentationTestRunner
//补充说明:
//测试路径: ElastosTest/Elastos/Framework/content/ComponentName/CComponentNameTest.cpp