软件测试中基于Lua脚本的自动化测试框架设计
自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常,在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的规程一步步执行测试,得到实际结果与期望结果的比较。在此过程中,为了节省人力、时间或硬件资源,提高测试效率,便引入了自动化测试的概念。
一、自动化测试背景
1. 被测对象为嵌入式系统中使用Lua脚本做胶合的一个个模块接口。需要编写Lua脚本调用这些接口对接口进行测试,运行环境为嵌入式系统中并非PC机。
2. 测试脚本能够起到回归测试及自动判断测试结果和输出测试报告
二、实现方法
主要参考XUnit框架机制实现测试套的封装,其封装的对象如下:
1. 测试环境
2. 自动化判断
3. 测试日志
4. 测试执行情况统计
5. 测试报告
三、测试框架
1. InitTestFrame() --初始化测试框架 ,只能执行一次,否则会影响测试结果统计 2. SetCurrModule("CurrModuleName") --当前测试模块的名字 3. WriteCaseName("CurrCaseName") --当前测试用例的名字 4. WriteCaseStep("CurrStepName") --当前测试步骤的名字 5. ret = AssertResult("sExpects","RealResult") --自动比较(选用) 6. WriteReport(ret,"sRealResult") --将测试结果写入测试报告文件中 7. GetStatistic() --获取测试执行情况统计 |
四、实现代码
1. 环境变量
--定义不同的环境变量,便于脚本的移植 if TestEntironment == nil then --如果没有定义TestEntironment Win32 = 1 Symbian = 2 TestEntironment = Win32 --TestEntironment = Symbian End if TestEntironment == Win32 then reportfile = "..\\TestCode\\TestReport.txt" --测试报告文件 else reportfile = "c:\\TestCode\\TestReport.txt" --测试报告文件 end |
2. 初始化测试框架
--初始化测试框架 function InitTestFrame() --定义存储各模块测试执行情况的表 tRunStatistic = {} tRunStatisticIndex = 0 --tRunStatistic的索引 CurrNGModuleIndex = 0 CurrNGCaseIndex = 0 --定义存储执行失败用例的表 tRunNG = {} end |
3. 测试套封装
function WriteCaseName(sCaseName) --标记测试用例名,写入测试报告文件 CurrCase = sCaseName local h = io.open(reportfile,"a") io.output(h) local sWriteStr = "\n【" .. sCaseName .."】" .. "\n" if TestEntironment == Win32 then print(sWriteStr) end io.write(sWriteStr) io.close(h) end function WriteCaseStep(sStep) --标记测试步骤,写入测试报告文件 CurrStep = sStep local h = io.open(reportfile,"a") io.output(h) local sWriteStr = " |--" .. sStep .. "\n" if TestEntironment == Win32 then print(sWriteStr) end io.write(sWriteStr) io.close(h) end function SetCurrModule(sModuleName) CurrModule = sModuleName temp = {Module = sModuleName,iRunCaseNum = 0,iOKCaseNum = 0,iNGCaseNum = 0} tRunStatisticIndex = tRunStatisticIndex + 1 table.insert(tRunStatistic,tRunStatisticIndex,temp) end |
4. 自动化判断
--自动比较期望结果与测试结果 function AssertResult(sExpects,RealResult) if sExpects == RealResult then return "OK" else return "NG" end end |
5. 测试日志
function WriteMsg(sMsg) local h = io.open(reportfile,"a") io.output(h) local sWriteStr = sMsg .. "\n" if TestEntironment == Win32 then print(sWriteStr) end io.write(sWriteStr) io.close(h) end |
6. 测试报告
--将测试结果写入测试报告文件 function WriteReport(sAssertResult,sRealResult) local h = io.open(reportfile,"a") io.output(h) local sWriteStr = " " .. sAssertResult .." (RealResult:" .. sRealResult .. ")\n" if TestEntironment == Win32 then print(sWriteStr) end io.write(sWriteStr) io.input(h) io.close(h) AddRunStatistic(sAssertResult) end |
7. 测试执行统计
function AddRunStatistic(sAssertResult) --统计测试执行情况 tRunStatistic[tRunStatisticIndex].iRunCaseNum = tRunStatistic[tRunStatisticIndex].iRunCaseNum + 1 if sAssertResult == "OK" then tRunStatistic[tRunStatisticIndex].iOKCaseNum = tRunStatistic[tRunStatisticIndex].iOKCaseNum + 1 else tRunStatistic[tRunStatisticIndex].iNGCaseNum = tRunStatistic[tRunStatisticIndex].iNGCaseNum + 1 --将失败的插入tRunNG if (tRunNG[CurrNGModuleIndex]~= nil)and(tRunNG[CurrNGModuleIndex][1] == CurrModule) then --存在Module记录 if (tRunNG[CurrNGModuleIndex] [2][CurrNGCaseIndex][1]~= nil)and(tRunNG[CurrNGModuleIndex][2] [CurrNGCaseIndex][1] == CurrCase) then --存在Case记录 --添加Step项 table.insert(tRunNG[CurrNGModuleIndex][2][CurrNGCaseIndex][2],CurrStep) else --增加Case项 table.insert(tRunNG[CurrNGModuleIndex][2],{CurrCase,{CurrStep}}) CurrNGCaseIndex = CurrNGCaseIndex + 1 end else --增加Module项 table.insert(tRunNG,{CurrModule,{{CurrCase,{CurrStep}}}}) CurrNGModuleIndex = CurrNGModuleIndex + 1 CurrNGCaseIndex = 1 --复位1 end end end --统计测试用例执行情况 function GetStatistic() WriteMsg("\nTestcase run statistic:") WriteMsg("**********************************************************************") WriteMsg("【ModuleName】".." 【Run】".." 【OK】".." 【NG】") WriteMsg("----------------------------------------------------------------------") for i = 1,table.getn(tRunStatistic) do --打印格式 s1 = "" for j = 1,24 - string.len(tRunStatistic[i].Module) do s1 = s1 .." " end s2 = "" for j = 1,17 - string.len(tRunStatistic[i].iRunCaseNum) do s2 = s2 .. " " end s3 = "" for j = 1,16 - string.len(tRunStatistic[i].iOKCaseNum) do s3 = s3 .. " " end WriteMsg(i..":"..tRunStatistic[i].Module..s1..tRunStatistic[i].iRunCaseNum..s2..tRunStatistic[i].iOKCaseNum..s3..tRunStatistic[i] .iNGCaseNum) end WriteMsg("**********************************************************************") --记录执行失败用例 GetRunNGCase() end --记录执行失败用例 function GetRunNGCase() WriteMsg("NG case info:") if table.getn(tRunNG)==0 then WriteMsg("No NG case,are you sure your case is perfect?") end for i = 1,table.getn(tRunNG) do WriteMsg(tRunNG[i][1]) --Module Name for j = 1,table.getn(tRunNG[i][2]) do WriteMsg(" |--"..tRunNG[i][2][j][1]) --Case Name for k = 1,table.getn(tRunNG[i][2][j][2]) do WriteMsg(" |--"..tRunNG[i][2][j][2][k]) -- Step Name end end end end |
五、使用方法
1. 测试用例
function db_read_case() WC("db_read_case"); WS("Step1") h = db.open(U(Sdir .. "dbComm")) --WM(h) --读数据 读取全部 for i = 1,TEST_RECORD do writeField = string.char(0x15) for j = 1,20 do writeField = writeField .. string.char(i+j) end readField = db.read(h,i,0,512) --被测接口 ret = AR(writeField,readField) if(ret == "NG")then WM("error:".. i) break end end WR(ret,"nil") --关闭打开的数据库 db.close(h) end --测试用例执行 InitTestFrame() WriteMsg("Database API test begin ...") SetCurrModule("Database") CreateEntironment() --创建测试环境 db_read_case() DestroyEntironment()--清除测试环境 WriteMsg("Database API test end!\n") GetStatistic() |
2. 测试报告
**************************************************** Tester :vince zhang Test Date:03/27/08 15:19:06 Database API test begin ... 【db_read_case】 |--Step1 OK (RealResult:nil) |--Step2 OK (RealResult:nil) Database API test end! Testcase run statistic: ********************************************************************** 【ModuleName】 【Run】 【OK】 【NG】 ---------------------------------------------------------------------- 1:Database 57 49 8 ********************************************************************** NG case info: Database |--db_read_case |--Step1 |--db_update_case |--Step4 |