zoukankan      html  css  js  c++  java
  • Python单元测试 -- Unittest(一)

    Unittest

    Unittest是Python的标准测试库,无需额外安装,是目前Python使用较为官方的测试框架。下面通过实例,一步一步了解如何使用Unittest。

    待测试代码如下,用于验证email和密码。

    # -*- coding: utf-8 -*-
    
    import re
    
    
    class CheckUserInfo:
    
        def check_mail(self, mail):
            flag = False
            str = '^[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+){0,4}@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+){0,4}$'
            if re.match(str, mail):
                flag = True
    
            return flag
    
        def check_pwd_len(self, pwd):
            '''密码长度不超过8位'''
            return len(pwd)>=8
    
        def check_pwd_contain_leter(self, pwd):
            '''密码包含大小写英文字母'''
            flag = False
            pattern = re.compile('[A-Z][a-z]+')
            match = pattern.findall(pwd)
    
            if match:
                flag = True
            return flag
    
        def check_pwd_contain_num(self, pwd):
            '''密码包含数字'''
            flag = False
            pattern = re.compile('[0-9]+')
            match = pattern.findall(pwd)
            if match:
                flag = True
            return flag

    TestCase — 单元测试用例

    对上面代码中的每个方法进行测试,就需要实现一个继承unittest.TestCase 测试用例类。

    # -*- coding: utf-8 -*-
    
    import unittest
    
    from com.unit_test.check_user_info import CheckUserInfo
    
    class CheckUserInfoTestCase(unittest.TestCase):
    
        def __init__(self, *args, **kwargs):
            super(CheckUserInfoTestCase, self).__init__(*args, **kwargs)
            self.check_user_info = CheckUserInfo()
    
        @classmethod
        def setUpClass(cls):
            print('setUpClass
    
    ')
    
        @classmethod
        def tearDownClass(cls):
            print('tearDownClass')
    
        def setUp(self):
            print('setUp')
    
        def tearDown(self):
            print('tearDown
    ')
    
        def test_check_mail(self):
            print('test_check_mail')
            self.assertEqual(True, self.check_user_info.check_mail('aa@bb'))
            self.assertEqual(False, self.check_user_info.check_mail('aa.bb'))
    
        def test_check_pwd_len(self):
            print('test_check_pwd_len')
            self.assertEqual(True, self.check_user_info.check_pwd_len('12345678'))
            self.assertEqual(False, self.check_user_info.check_pwd_len(''))
            self.assertEqual(False, self.check_user_info.check_pwd_len('1'))
            self.assertEqual(True, self.check_user_info.check_pwd_len('123456789'))
    
        def test_check_pwd_contain_letter(self):
            print('test_check_pwd_contain_leter')
            self.assertEqual(True, self.check_user_info.check_pwd_contain_leter('1qazXSW@'))
            self.assertEqual(False, self.check_user_info.check_pwd_contain_leter('12345678'))
            self.assertEqual(False, self.check_user_info.check_pwd_contain_leter(''))
    
        def test_check_pwd_contain_num(self):
            print('test_check_pwd_contain_num')
            self.assertEqual(True, self.check_user_info.check_pwd_contain_num('1qazXSW@'))
            self.assertEqual(False, self.check_user_info.check_pwd_contain_num('qwertasdfg'))
            self.assertEqual(False, self.check_user_info.check_pwd_contain_num(''))
    
        def aaa(self):
            print('test_check_pwd_contain_num')
            self.assertEqual(True, self.check_user_info.check_pwd_contain_num('1qazXSW@'))
    if __name__ == '__main__':
        unittest.main()

    执行结果如下:

    ...
    setUpClass
    
    setUp
    test_check_mail
    tearDown
    
    setUp
    test_check_pwd_contain_leter
    tearDown
    
    setUp
    test_check_pwd_contain_num
    tearDown
    
    setUp
    test_check_pwd_len
    tearDown
    
    tearDownClass
    
    Ran 4 tests in 0.013s
    
    OK
    
    Process finished with exit code 0

    使用“unittest.main()”,通过观察上面的测试代码以及执行结果,可以发现:

    testXXX方法

    使用“unittest.main()”执行测试用例时,每个测试方法必须以“test”开头,否则Unittes无法识别。例如,上面代码中的“aaa”方法未执行。

    测试方法执行顺序

    每个测试方法执行顺序并不是按照代码的书写顺序执行,而是按照前缀“test”后的字母顺序执行的。

    setUp()方法

    setUp()方法一般用来准备测试环境,在每个测试方法执行之前执行。

    tearDown()方法

    tearDown()方法一般用来清理测试环境,在每个测试方法执行之后执行,且不论测试方法执行是否成功。

    setUpClass()方法

    setUpClass()方法一般用来在所有测试方法执行之前准备一次测试环境,必须使用“@classmethod”装饰符,在所有测试方法执行前执行。

    tearDownClass()

    tearDownClass()方法一般用来在所有测试方法结束之后清理一次测试环境,必须使用“@classmethod”装饰符,在所有测试方法都执行完成否执行。

    skip装饰器

    不希望执行某个测试方法时,可以使用skip装饰器。skip装饰器共有三种:unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason)。

    • unittest.skip(reason):无条件跳过
    # -*- coding: utf-8 -*-
    
    import unittest
    
    from com.unit_test.check_user_info import CheckUserInfo
    
    class CheckUserInfoTestCase(unittest.TestCase):
    
        ......
    
        @unittest.skip('skip test_bbb method')
        def test_bbb(self):
            print('test_bbb')
    
    ......

    部分执行结果如下:

    ...
    Skipped: skip test_bbb method
    ...
    • unittest.skipIf(condition, reason):当condition为True时跳过
    # -*- coding: utf-8 -*-
    
    import unittest
    
    from com.unit_test.check_user_info import CheckUserInfo
    
    class CheckUserInfoTestCase(unittest.TestCase):
    
        ......
    
        @unittest.skipIf(1<2, 'skip test_ccc method')
        def test_ccc(self):
            print('test_ccc')
    
    ......

    部分执行结果如下:

    ...
    Skipped: skip test_ccc method
    ...
    • unittest.skipUnless(condition, reason):当condition为False时跳过
    # -*- coding: utf-8 -*-
    
    import unittest
    
    from com.unit_test.check_user_info import CheckUserInfo
    
    class CheckUserInfoTestCase(unittest.TestCase):
    
        ......
    
        @unittest.skipUnless(1>2, 'skip test_ddd method')
        def test_ddd(self):
            print('test_ddd')
    
    ......

    部分执行结果如下:

    ...
    Skipped: skip test_ddd method
    ...

    那么,如何控制测试方法的执行顺序呢?如何执行非“test”开头的测试方法?接下来了解一下TestSuite。

    TestSuite — 单元测试用例合集

    通过上面的测试用例代码,可以发现无法指定测试方法的顺序。那么通过unittest.TestSuite,就可以按照业务逻辑顺序执行测试方法。

    # -*- coding: utf-8 -*-
    
    import unittest
    
    from com.unit_test.check_user_info_test_case import CheckUserInfoTestCase
    
    
    if __name__ == '__main__':
        suite = unittest.TestSuite()
        tests = [
            CheckUserInfoTestCase('test_check_mail'),
            CheckUserInfoTestCase('test_check_pwd_len'),
            CheckUserInfoTestCase('test_check_pwd_contain_letter'),
            CheckUserInfoTestCase('test_check_pwd_contain_num')
        ]
        suite.addTests(tests)
    
        runner = unittest.TextTestRunner()
        runner.run(suite)

    执行结果如下:

    ...
    Ran 4 tests in 0.002s
    
    OK
    setUpClass
    
    
    setUp
    test_check_mail
    tearDown
    
    setUp
    test_check_pwd_len
    tearDown
    
    setUp
    test_check_pwd_contain_leter
    tearDown
    
    setUp
    test_check_pwd_contain_num
    tearDown
    
    tearDownClass
    
    Process finished with exit code 0

    通过数组指定测试方法的执行顺序

    tests = [
        CheckUserInfoTestCase('test_check_mail'),
        CheckUserInfoTestCase('test_check_pwd_len'),
        CheckUserInfoTestCase('test_check_pwd_contain_letter'),
        CheckUserInfoTestCase('test_check_pwd_contain_num')
    ]
    suite.addTests(tests)

    通过addTests()方法指定测试方法的执行顺序

    suite.addTest(CheckUserInfoTestCase('test_check_mail'))
    suite.addTest(CheckUserInfoTestCase('test_check_pwd_len'))
    suite.addTest(CheckUserInfoTestCase('test_check_pwd_contain_letter'))
    suite.addTest(CheckUserInfoTestCase('test_check_pwd_contain_num'))

    无法指定测试方法执行顺序的unittest.TestLoader()

    通过unittest.TestLoader()加载TestCase,测试方法是按照前缀“test”后的字母顺序执行的。

    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(CheckUserInfoTestCase))

    执行非“test”开头的测试方法

    在TestCase中的示例代码中,可以看到,测试方法名不是以“test”开头时是不会被执行的。那么,通过TestSuite就可以完美解决这个问题。

    suite.addTest(CheckUserInfoTestCase('aaa'))


  • 相关阅读:
    timequest 中set input delay set output delay 的使用
    ALTERA的FPGA命名规则
    modelsim仿真常用系统函数
    altium布局布线原则
    altium常用快捷键记录
    第五篇:使用无缓冲IO函数读写文件
    第四篇:“ 不确定 "限制值的使用
    第三篇:POSIX标准中的 “ 限制 ”
    第二篇:库函数和系统调用的区别
    hdu 4284(状压dp)
  • 原文地址:https://www.cnblogs.com/Rvin/p/9272023.html
Copyright © 2011-2022 走看看