zoukankan      html  css  js  c++  java
  • Python3+unitest自动化测试初探(下篇)


    unittest官方文档
    本篇随笔承接:
    Python3+unitest自动化测试初探(中篇)
    Python3+unitest自动化测试初探(上篇)

    9、用例结果校验

    用unittest来完成自动化测试时,结果校验无疑是非常重要的。用例校验不完整或者校验过于简单,是无法发现产品的缺陷或Bug的。就自动化测试来而言,其目的是代替部分手动测试,将测试人员从繁重重复的功能测试中解放出来。试想一下,一些缺少校验或简单校验的用例运行完后通过率即使达到100%,这能说明产品或版本没有任何问题吗?能够增强版本发布的信心吗?unittest提供了很多断言方法用于测试结果的校验。常用的断言方法如下:


    所有的断言方法都提供一个可选参数msg,用于在测试失败时显示。

    • assertEqual(a, b,msg=None):校验a是否等于b,如果相等,测试通过,反之则测试失败。msg为可选参数,如果传入了该参数,在测试失败时会打印。
    >>> class assertTest(unittest.TestCase):
    ... 	pass
    ... 
    >>> ast1 = assertTest() 
    
    >>> ast1.assertEqual(1,2,msg="1 is not equal to 2")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/lib/python3.7/unittest/case.py", line 839, in assertEqual
        assertion_func(first, second, msg=msg)
      File "/usr/local/lib/python3.7/unittest/case.py", line 832, in _baseAssertEqual
        raise self.failureException(msg)
    AssertionError: 1 != 2 : 1 is not equal to 2
    
    • assertNotEqual(a, b, msg=None):校验a是否不等于b,如果不相等,测试通过。反之则测试失败。
    • assertTrue(x,msg=None):验证x是否为True,x可以为值或表达式,x为True则测试通过。反之,则测试失败,msg为可选参数,如果传入了该参数,在测试失败时会打印。
    >>> ast1.assertTrue(1=2,msg="1=2,False")
      File "<stdin>", line 1
    SyntaxError: keyword can't be an expression
    >>> ast1.assertTrue(1==2,msg="1=2,False")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/lib/python3.7/unittest/case.py", line 692, in assertTrue
        raise self.failureException(msg)
    AssertionError: False is not true : 1=2,False
    
    
    • assertIs(a, b):判断a is b是是否成立。等价于判断id(a) == id(b)是否成立,如果成立,则测试通过。反之,测试失败。
    • assertIsNone(x):判断x是否为None。如果为None则测试通过,反之,测试失败。
    • assertIn(a, b):判断a是否在b中。如果在,则测试通过,反之,测试失败。
    • assertIsInstance(a, b):判断a是否为b的实例。如果是,则测试通过,反之,测试失败。

    unittest还提供了如下方法用于检查异常,警告,日志信息。图片来自unittest官方文档。

    检查异常,警告,日志的使用方法大同小异。在此不一一说明了,下面举例说明assertRaises(exc, fun, *args, **kwds)和assertRaises(exc, fun, *args, **kwds)的用法。
    [ 示例1 ] assertRaises()的用法

    #coding:utf-8
    '''
    定义一个除法的函数
    当y==0时,会抛出错误ZeroDivisionError
    '''
    import unittest
    def div(x,y):
            return  x/y
    
    #定义一个测试类assertTest,继承于unittest.TestCase
    class assertTest(unittest.TestCase):
        #pass表示什么也不做
        pass
    ast2 = assertTest()
    '''
    第一个参数为异常的类型
    第二个为方法名称
    后面为方法的参数
    '''
    ast2.assertRaises(ZeroDivisionError,div,1,0)
    print("---------------------------------------")
    ast2.assertRaises(ZeroDivisionError,div,1,1)
    

    调用div(1,1)不会抛出异常ZeroDivisionError,所以assertRaises()测试失败,上述代码运行结果如下:

    如果只传入了expetion或msg参数,就可以在with上下文管理器中测试一段代码而不仅仅是测试函数,就像下面这样。

    with ast2.assertRaises(ZeroDivisionError):
         div(1,1)
    
    with ast2.assertRaises(ZeroDivisionError):
        div(1,0)
    
    

    运行结果如下:

    [ 示例2 ] assertRaises()的用法

    #导入warnings模块
    import warnings
    #定义一个简单的函数,打印级别为UserWarning的告警
    def warnTest():
         warnings.warn("This is warning test")
    
    ast2.assertWarns(UserWarning,warnTest)
    print("--------------------------------")
    with ast2.assertWarns(UnicodeWarning):
        warnTest()
    

    warnTest()函数不会打印UnicodeWarning级别的告警,所以第二个告警校验会失败,运行结果如下:


    点击这里返回本篇目录

    10、跳过用例

    在一些场景下并不会执行所有的用例,而是选择性跳过一部分用例。unittest支持跳过单个用例或整个测试类。跳过用例需要用到unittest.skip()装饰器。

    • @unittest.skip(reason):无条件跳过单个用例或测试类,reason是跳过的原因。
    • @unittest.skipIf(condition, reason):if条件成立则跳过单个用例或测试类,reason是跳过的原因。
    • @unittest.skipUnless(condition, reason):条件为False则跳过单个用例或测试类,reason是跳过的原因。
    • @unittest.expectedFailure:标记测试用例为失败,不会出现在统计结果中。
    • exception unittest.SkipTest(reason):跳过用例并抛出异常。

    [ 示例3 ]:直接跳过注册功能的用例
    对userRegTest.py做如下修改,并执行userRegTest.py:

        @unittest.skip("skip test case of user reg")
        def test_pwdlenerr_L1(self):
            print("test case:test_pwdlenerr_L1")
            res = self.user1.userReg()
            self.assertEqual(res,"passwordLenError")
    
        #测试场景:正常注册
        @unittest.skipIf(2>1,"skip if condiction")
        def test_regsucess_L0(self):
            print("test case:test_regsucess_L0")
            res = self.user2.userReg()
            self.assertEqual(res,"regSucess")
    
        #测试场景:用户名重名
        @unittest.skipUnless(1<0,"skip unless.")
        def test_regagain_L1(self):
            print("test case:test_regagain_L1")
            res = self.user3.userReg()
            self.assertEqual(res,"SameNameError")
    
    

    执行结果如下:

    11、Test Discovery

    unittest支持用例发现功能,在unittest.defaultTestLoader中实现。使用的时候需要传入两个参数:寻找的起始目录,匹配的测试文件的格式(默认test*.py)。用例发现也支持命令行模式。

    [ 示例4 ]:testDiscover

        startPath = './testCases'
        discover = unittest.defaultTestLoader.discover(start_dir=startPath,pattern='*Test.py')
        print(discover)
    

    运行结果:

    12、加载用例

    unittest支持从模块和测试类中提取测试用例创建测试套。在class unittest.TestLoader中实现。TestLoader常见的加载方法如下:

    • loadTestsFromTestCase(testCaseClass):从unittest.TestCase的子类即测试类中加载用例并返回测试套。
    • loadTestsFromName(name,module=None):从特定的字符串说明符中加载用例并返回测试套。
    • loadTestsFromNames(names,module=None):用法和 loadTestsFromName(name,module=None)类似,不同的是它可以接受字符串说明符列表,而不是一个。
    • loadTestsFromModule(module, pattern=None):从模块中加载所有测试用例,返回一个测试套件。
    • getTestCaseName(testCaseClass):返回一个有序的包含在testCaseClass中的方法名列表。

    [示例5 ] :TestLoader用法举例

    
    #coding:utf-8
    
    import unittest
    import testCases.userLoginTest,testCases.userRegTest
    from testCases.userRegTest import regTest
    from testCases.userLoginTest import loginTest
    
    loader = unittest.TestLoader()
    
    print("从测试类loginTest加载所有的用例:")
    caseInLoginTest = loader.getTestCaseNames(loginTest)
    print(caseInLoginTest)
    
    print("从测试模块中加载用例:")
    loadByModule = loader.loadTestsFromModule(testCases.userLoginTest)
    print(loadByModule)
    
    print("从测试类中加载用例:")
    loadByTestClass = loader.loadTestsFromTestCase(regTest)
    print(loadByTestClass)
    print("从特定的字符串标识符中加载用例")
    
    loadBySpecifier = loader.loadTestsFromName("regTest.test_regagain_L1")
    print(loadBySpecifier)
    
    print("从字符符标识符列表中加载用例")
    specStrs = ["regTest.test_regagain_L1","test_regsucess_L0"]
    loadBySpecifiers = loader.loadTestsFromNames(specStrs)
    print(loadBySpecifiers)
    
    

    运行结果如下:

    在发布时间紧张,产品迭代频繁的情况下,很多时候上线一个新特性,对已发布的老特性采用的回归策略是:只执行L0即(Level 0)级别的测试用例。这个在unittest里面怎么实现呢?解决方案是:

    1. 规范特性L0用例的命名格式,比如:test_xxx_L0.
    2. 加载用例
    3. 通过正则表达式匹配出L0级别的用例集合,然后交给test runner执行。

    (完)
    点击这里返回本篇目录

  • 相关阅读:
    java操作生成jar包 和写入jar包
    jboss配置jndi连接池
    windows 域的LDAP查询相关举例
    LDAP error Code 及解决方法
    HDU 6417
    CF1299D Around the World
    codechef Chef and The Colored Grid
    Educational Codeforces Round 82 (Rated for Div. 2)
    CF1237F Balanced Domino Placements
    CF1254E Send Tree to Charlie
  • 原文地址:https://www.cnblogs.com/webDepOfQWS/p/10732345.html
Copyright © 2011-2022 走看看