unittest中合理使用setUp与tearDown

今天在写自动化测试用例设计的时候,遇到一个小坑,贴出部分代码如下:

class order_MT(unittest.TestCase):

    def setUp(self):
        self.driver = login()
        To_manage_order(self.driver)

    def test_search_order(self):
        search_order_test(self.driver)

    def test_new_order(self):
        add_order_msg(self.driver)

    def test_Order_num(self):
        Order_num_Verification(self.driver)

    def teardown(self):
        self.quit()

发现所有用例结束执行结束只调用了一次teardown。 然后仔细查看发现是d要大写。

既然说到这了就扯一扯其他问题:
用例的执行顺序并不是按照先后顺序的,做个小实验:

import unittest

class Test_setup_and_teardwon(unittest.TestCase):

    def setUp(self):
        print('set up')

    def tearDown(self):
        print('tear down')

    def test_case_B(self):
        print('run B')

    def test_case_A(self):
        print('run A')

    def test_case_C(self):
        print('run C')

if __name__ == '__main__':
    unittest.main()

运行结果:

set up
.run A
tear down
set up
run B
tear down
.set up
run C
tear down

——————————————————————————————————
Ran 3 tests in 0.000s

OK
[Finished in 0.2s]

在unittest中用例执行的先后顺序是根据数字、字母的先后顺序来判定的。那么有什么方法可以让它按照预定的顺序执行呢?

1.用字母、数字先后顺序排序。(这个有比较明显的缺点:用例名称会不够美观、杂乱无章)

2.用testsuite控制用例加载顺序。(缺点是,当case较多 时,逐个添加非常麻烦)

第二种办法的实例:

import unittest

class Test_setup_and_teardwon(unittest.TestCase):

    def setUp(self):
        print('set up')

    def tearDown(self):
        print('tear down')

    def test_case_B(self):
        print('run B')

    def test_case_A(self):
        print('run A')

    def test_case_C(self):
        print('run C')

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(Test_setup_and_teardwon("test_case_A"))
    suite.addTest(Test_setup_and_teardwon("test_case_B"))
    suite.addTest(Test_setup_and_teardwon("test_case_C"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

执行结果如下:

set up
.run A
tear down
set up
run B
tear down
set up
run C
tear down
——————————————————————
Ran 3 tests in 0.000s

OK
[Finished in 0.2s]

可见两种方法都是可行的。

但是随之而来的问题就是:
当下一个用例的执行需要依赖上一个用例的执行结果时,应该怎么办?

先来验证一次每个用例是否在结尾处都会执行一次tearDown:

import unittest

class Test_setup_and_teardwon(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 = self.a*2
        b = self.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))


if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(Test_setup_and_teardwon("test_case_A"))
    suite.addTest(Test_setup_and_teardwon("test_case_B"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

运行结果:

set up over :
a = 2, b = 3 

run A over :
a = 4, a = 6 

tear down over :
a = 0, b = 0
__________________________________________________________
set up over :
.a = 2, b = 3 

run B over :
a= 4, b = 6 

tear down over :
a = 0, b = 0
__________________________________________________________
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK
[Finished in 0.2s]

可见确实每个case运行结束之后都会调用tearDown,那么如何避免呢?

通常我会使用两个方法:

1.在需要依赖的case中,将上一个case单独拎出来做一个公用的方法。然后在进入这个case时先调用该方法。例如caseB需要caseA返回的结果,那么我先将caseA封装成一个通用的方法,根据传入的参数不同返回不同的值。然后在caseB中获取返回的值,作为caseB开始前的另一种变相的 ‘setup’。

修改代码如下:

import unittest

def set_A(a, b):
    a = a*2
    b = b*2
    return (a, b)

class Test_setup_and_teardwon(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, 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(Test_setup_and_teardwon("test_case_A"))
    suite.addTest(Test_setup_and_teardwon("test_case_B"))
    suite.addTest(Test_setup_and_teardwon("test_case_C"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

结果:

set up over :
.a = 2, b = 3 

run A over :
a = 4, a = 6 

tear down over :
a = 0, b = 0
__________________________________________________________
set up over :
a = 2, b = 3 

run B over :
a= 8, b = 12 

tear down over :
.a = 0, b = 0
__________________________________________________________
set up over :
a = 2, b = 3 

run C over :
.a = 8, a = 12 

tear down over :
a = 0, b = 0
__________________________________________________________

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
[Finished in 0.1s]

可见如此做确实可以保证保持用例依赖性的同时,也保证其他用例的测试环境的“干净”。

但是在测试用例难以解耦的情况下,每写下一个用例就要封装上一个用例的方法,这会导致代码长度翻倍增长。

因此在此处对于用例之间依赖性较强的模块,控制setUp和tearDown方法只执行一次就很有必要。

2.使用修饰器控制setUp和tearDown的执行条件。

代码如下:

import unittest

def set_A(a, b):
    a = a*2
    b = b*2
    return (a, b)

class Test_setup_and_teardwon(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(Test_setup_and_teardwon("test_case_A"))
    suite.addTest(Test_setup_and_teardwon("test_case_B"))
    suite.addTest(Test_setup_and_teardwon("test_case_C"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

执行结果:

set up over :
a = 2, b = 3 

run A over :
a = 4, a = 6 

..run B over :
a= 8, b = 12 

run C over :
a = 8, a = 12 

tear down over :
a = 0, b = 0
__________________________________________________________
.
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
[Finished in 0.2s]

因此,将不同模块对于用例之间的解耦很有必要,这样可以给不同用例提供整洁的测试环境。
耦合度较高的用例可以配合使用上述几种方法设计测试环境。

你可能感兴趣的:(python)