上一期讲解了类方法和静态方法在类中的调用方法和作用,这一期讲解类方法修饰器在自动化测试中的解耦作用。首先看以下一个测试Demo,代码如下,和输出结果如 图1, 可见测试用例输出中,并不是按代码顺序输出,而是按字母顺序输出,这个有比较明显的缺点:用例名称会不够美观、杂乱无章。
import unittest
class TestCase(unittest.TestCase):
def setUp(self):
print('set up')
def tearDown(self):
print('tear down')
def test_case_B(self):
print('test_case_B')
def test_case_A(self):
print('test_case_A')
def test_case_C(self):
print('test_case_C')
if __name__ == '__main__':
unittest.main()
图1
另外我们可以用 testsuite控制用例加载顺序,缺点是,当case较多 时,逐个添加非常麻烦。具体代码如下,输出结果如 图2, 可见输出结果也是一样的,说明这两种方法都可行的。但如果当下一个测试用例的执行需要依赖上一个用例的执行结果时,这应该怎么办呢?
import unittest
class TestCase(unittest.TestCase):
def setUp(self):
print('set up')
def tearDown(self):
print('tear down')
def test_case_B(self):
print('test_case_B')
def test_case_A(self):
print('test_case_A')
def test_case_C(self):
print('test_case_C')
if __name__ == '__main__':
suite = unittest.TestSuite() # 添加 suite 容器
suite.addTest(TestCase('test_case_A'))
suite.addTest(TestCase('test_case_B'))
suite.addTest(TestCase('test_case_C'))
runner = unittest.TextTestRunner()
runner.run(suite)
图2
再举另外一个测试用例的例子,代码如下,从 图3 的输出结果看,可见每个测试用例结束后都会调用 tearDown,那该如何避免呢?
import unittest
class TestCase(unittest.TestCase):
def setUp(self):
self.a = 2
self.b = 3
print('set up')
print('a = %s, b = %s \n'%(self.a, self.b))
def tearDown(self):
a = 0
b = 0
print('tear down')
print('a = %s, b = %s'%(a, b))
print('__________________________________________________________')
def test_case_B(self):
a = self.a*3
b = self.b*3
print('test_case_B')
print('a= %s, b = %s \n'%(a, b))
def test_case_A(self):
a = self.a*3
b = self.b*3
print('test_case_A')
print('a = %s, b = %s \n'%(a, b))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestCase('test_case_A'))
suite.addTest(TestCase('test_case_B'))
runner = unittest.TextTestRunner()
runner.run(suite)
图3
方法一: 在需要依赖的用例中,把上一个用例单独作为一个公用的方法,然后在进入这个用例时先调用该方法。例如用例B需要用例A返回的结果,那么可以把用例A封装成一个通用的方法,根据传入的params不同返回不同的值。然后在用例B中获取返回的值,作为用例B开始前的另一种的 ‘setUp’, 把代码稍微修改一下,输出结果如 图4
import unittest
def set_A(a, b):
a = a*2
b = b*2
return a, b
class TestCase(unittest.TestCase):
def setUp(self):
self.a = 2
self.b = 3
print('set up over :')
print('a = %s, b = %s \n'%(self.a, self.b))
def tearDown(self):
a = 0
b = 0
print('tear down over :')
print('a = %s, b = %s'%(a, b))
print('__________________________________________________________')
def test_case_B(self):
a, b = set_A(self.a, self.b)
a = a*2
b = b*2
print('run B over :')
print('a= %s, b = %s \n'%(a, b))
def test_case_A(self):
a = self.a*2
b = self.b*2
print('run A over :')
print('a = %s, b = %s \n'%(a, b))
def test_case_C(self):
a = self.a*4
b = self.b*4
print('run C over :')
print('a = %s, a = %s \n'%(a, b))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestCase("test_case_A"))
suite.addTest(TestCase("test_case_B"))
suite.addTest(TestCase("test_case_C"))
runner = unittest.TextTestRunner()
runner.run(suite)
图4
在测试用例难以解耦的情况下,每写下一个用例就要封装上一个用例的方法,这会导致代码长度翻倍增长。因此控制setUp和tearDown方法只执行一次是必须的,把代码再稍微修改一下,这时修饰器@classmethod登场了,输出结果如 图5,可见setUp 和 tearDown 只输出一次。在实际的自动化模块测试中,主要是具体问题具体分析整个流程思路,不一定必须要控制setUp 和 tearDown 只输出一次的,具体要在实际测试经验中而决定。
import unittest
def set_A(a, b):
a = a*2
b = b*2
return a, b
class TestCase(unittest.TestCase):
@classmethod
def setUpClass(self):
self.a = 2
self.b = 3
print('set up over :')
print('a = %s, b = %s \n'%(self.a, self.b))
@classmethod
def tearDownClass(self):
a = 0
b = 0
print('tear down over :')
print('a = %s, b = %s'%(a, b))
print('__________________________________________________________')
def test_case_B(self):
a, b = set_A(self.a, self.b)
a = a*2
b = b*2
print('run B over :')
print('a= %s, b = %s \n'%(a, b))
def test_case_A(self):
a = self.a*2
b = self.b*2
print('run A over :')
print('a = %s, a = %s \n'%(a, b))
def test_case_C(self):
a = self.a*4
b = self.b*4
print('run C over :')
print('a = %s, a = %s \n'%(a, b))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestCase("test_case_A"))
suite.addTest(TestCase("test_case_B"))
suite.addTest(TestCase("test_case_C"))
runner = unittest.TextTestRunner()
runner.run(suite)
图5