至于为什么要动态生成unittest执行脚本,以及设计思路,代码阅读参考前文,传送门。好了,本文我们就上一篇文章中的问题做一下分析,记录一下填坑之路吧,这个坑真特么深,挣扎了好久才出来。
首先我们先说一下问题在哪,因为使用了闭包,闭包会绑定变量无法清除无法更改,假如我第一次运行testall函数循环两次,第一次是正常的,第二次运行testall函数循环一次,那么生成的报告就会出现问题,会出现第一次运行的结果。即是:后一次循环运行只要比前一次循环少,那么report一定会出现前一次的结果,必先的bug。
好了,我们聊一下前文动态生成unittest执行脚本的坑有多深吧,主要涉及闭包,又因为闭包循环调用unittest的Test类添加方法组成suite,大家都知道Python的闭包会绑定变量,无法清除无法改变,我们把相关代码贴出来吧,方便看。
1 class Test(unittest.TestCase): # TestCase类 2 "测试类" 3 4 def begin_req(self, apidata): # 类方法 5 back = run_single_testcase(apidata) # 调用请求 6 YQ = 200 # 结果对比 7 SJ = back.status_code 8 self.assertEqual(SJ, YQ) 9 10 def demo(apidata): # 闭包 11 def tool(self): 12 Test.begin_req(self, apidata) # 调用Test方法 13 14 setattr(tool, ‘__doc__‘, u‘测试%s‘ % str(apidata[‘name‘])) 15 return tool 16 17 def testall(apidata): # 循环调用闭包 18 for i in range(len(apidata)): 19 setattr(Test, ‘test_‘ + str(i + 1), demo(apidata[i])) 20 21 def suite(Apidata): # 调用testall拼装Test类,组装suit 22 testall(Apidata) 23 suit = unittest.makeSuite(Test) 24 return suit
代码释义: 类Test继承unittest.TestCase没啥好说的,方法demo闭包内部函数tool,tool方法的第一个参数self是Test类(我理解为指针指向Test类),函数testall循环调用闭包,函数suite我上面注释写的很清楚了
这个坑有很大的迷惑性,我有很大一部分时间都在关注闭包函数,我认为是闭包导致的,一直在研究闭包哪里出错了,还有要如何更改闭包函数的参数,用了很多方法,什么容器装参数,后面删除容器成员啥的,全用上了...MMP...结果确实是闭包导致的,但是问题没有出在闭包函数处,要理解闭包请参考其他文章,传送门,我们就不白话了,上解决的代码吧
1 def testall(apidata): 2 nameList = [] 3 for i in range(len(apidata)): 4 name = ‘test_‘ + str(i + 1) 5 setattr(Test, name, demo(apidata[i])) 6 nameList.append(name) 7 return nameList 8 9 def suite(Apidata): 10 nameList = testall(Apidata) 11 suites = unittest.TestSuite() 12 for i in nameList: 13 suites.addTest(Test(i)) 14 return suites
主要修改了testall函数和suite函数,其实问题出在suite函数里,原有函数如下代码
1 def suite(Apidata): # 调用testall拼装Test类,组装suit 2 testall(Apidata) 3 suit = unittest.makeSuite(Test) 4 return suit
第三行中makeSuite函数,是指一次性添加Test类的方法到suite,结果闭包绑定的对象(python一切皆对象)在Test里,第一次运行组装的Test类方法被闭包绑定,后一次运行如果比前一次少,那么就会有没有被覆盖的方法,就会出现错误,所以修改makeSuite函数为addTest函数,问题就解决了,我研究了很久的闭包啊,结果问题出在了Test类上,真心心累。文笔太差..见谅..多谢..