zoukankan      html  css  js  c++  java
  • 单元测试模块unittest使用学习

    工作原理:
    unittest中最核心的四个概念是:test case, test suite, test runner, test fixture。
    
    一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),
    执行测试代码(run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。 而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。 TestLoader是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例。 TextTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite
    /TestCase中的run(result)方法。 测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。 而对一个测试用例环境的搭建和销毁,是一个fixture。

    三个模块:
    1、程序或基础类:

    def add(a, b):
        return a+b
    
    def minus(a, b):
        return a-b
    
    def multi(a, b):
        return a*b
    
    def divide(a, b):
        return a/b

    2、测试用例

    class TestMathFunc(unittest.TestCase):# 一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例
    
        def test_add(self):  # 每个测试方法都需要以test开头,否则是不会被unittest识别到
              """Test method add(a, b)"""
              self.assertEqual(3, add(1, 2))  # 判断相等
              self.assertNotEqual(3, add(2, 2))  # 判断不相等
        def test_minus(self):
            """Test method minus(a, b)"""
            self.assertEqual(1, minus(3, 2))
    
        def test_multi(self):
            """Test method multi(a, b)"""
            self.assertEqual(6, multi(2, 3))
    
          def test_divide(self):
            """Test method divide(a, b)"""
            self.assertEqual(2, divide(6, 3))
            self.assertEqual(2.5, divide(5, 2))
    
    
     if __name__ == '__main__':
        unittest.main() #main传参控制报告详细程度  verbosity = ,默认是1,不输出每一条测试用例的结果是0,输出详细的测试用例执行结果是2

    3、执行测试

    import unittest
    from test_mathfunc import TestMathFunc #传入测试用例,
    
    if __name__=='__main__':
      suite = unittest.TestSuite()
    
      #按指定顺序执行
      tests = [TestMathFunc("test_add"),TestMathFunc("test_minus"),TestMathFunc('test_divide')]
      suite.addTests(tests)
    
      # 直接用addTest方法添加单个TestCase
      # suite.addTest(TestMathFunc("test_multi"))
    
      # 用addTests + TestLoader
      # loadTestsFromName(),传入'模块名.TestCase名'
      # suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc'))
      # suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc']))  # loadTestsFromNames(),类似,传入列表
    
      # loadTestsFromTestCase(),传入类TestCase
      # suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
    
      runner = unittest.TextTestRunner(verbosity=2) #测试结果展示内容
      runner.run(suite) #执行测试

    测试用例的保存:

    修改执行测试文件:

    import
    unittest from test_mathfunc import TestMathFunc if __name__=='__main__': suite = unittest.TestSuite() # tests = [TestMathFunc("test_add"),TestMathFunc("test_minus"),TestMathFunc('test_divide')] # suite.addTests(tests) # 直接用addTest方法添加单个TestCase # suite.addTest(TestMathFunc("test_multi")) # 用addTests + TestLoader # loadTestsFromName(),传入'模块名.TestCase名' # suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc')) # suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc'])) # loadTestsFromNames(),类似,传入列表 # loadTestsFromTestCase(),传入leiTestCase suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc)) with open('test_Report.txt','a') as f: #打开要保存结果的文件 runner = unittest.TextTestRunner(stream=f,verbosity=2)#stream 写入内容 runner.run(suite)

    准备环境、清理环境:

    test fixture之setUp() 和tearDown()

    这两个方法在每个测试方法执行前以及执行后执行一次

    修改测试用例文件
    
    import unittest
    from mathfunc import *
    
    
    class TestMathFunc(unittest.TestCase):
        """Test mathfuc.py"""
    
        def setUp(self):  #setUp用来为测试准备环境
            print "do something before test.Prepare environment."
    
        def tearDown(self): #tearDown 用来清理测试环境
            print "do something after test.Clean up."
    
        def test_add(self):
            """Test method add(a, b)"""
            print "add"
            self.assertEqual(3, add(1, 2))
            self.assertNotEqual(3, add(2, 2))
    
        def test_minus(self):
            """Test method minus(a, b)"""
            print "minus"
            self.assertEqual(1, minus(3, 2))
    
        def test_multi(self):
            """Test method multi(a, b)"""
            print "multi"
            self.assertEqual(6, multi(2, 3))
    
        def test_divide(self):
            """Test method divide(a, b)"""
            print "divide"
            self.assertEqual(2, divide(6, 3))
            self.assertEqual(2.5, divide(5, 2))

    如果想要在所有case执行之前准备一次环境,并在所有case执行结束之后再清理环境,我们可以用 setUpClass() 与 tearDownClass():

    class TestMathFunc(unittest.TestCase):
        """Test mathfuc.py"""
    
        @classmethod
        def setUpClass(cls): #执行测试前运行
            print ("This setUpClass() method only called once.")
        @classmethod
        def tearDownClass(cls): #所有测试用例执行完毕后运行
            print ("This tearDownClass() method only called once too.")
    
        def test_add(self):
            """Test method add(a, b)""" 
            print ("add")
            self.assertEqual(3, add(1, 2))
            self.assertNotEqual(3, add(2, 2))

    跳过当前用例:

    1.skip装饰器:

    class TestMathFunc(unittest.TestCase):
        """Test mathfuc.py"""
    
        ...
    
        @unittest.skip("I don't want to run this case.")
        def test_divide(self):
            """Test method divide(a, b)"""
            print "divide"
            self.assertEqual(2, divide(6, 3))
            self.assertEqual(2.5, divide(5, 2))

    unittet可以分无条件忽略和有条件忽略,通过装饰器实现
    @unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。
    @unittest.skipIf(reason): skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。
    @unittest.skipUnless(reason): skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。
    @unittest.expectedFailure(): expectedFailure()测试标记为失败。

    @self.skipTest :函数体内使用,

    class MyTestCase(unittest.TestCase):  
        @unittest.skip("demonstrating skipping")  
        def test_nothing(self):  
            self.fail("shouldn't happen")  
        @unittest.skipIf(mylib.__version__ < (1, 3),  
                         "not supported in this library version")  
        def test_format(self):  
            # Tests that work for only a certain version of the library.  
            pass  
        @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")  
        def test_windows_support(self):  
            # windows specific testing code  
            pass  
        @unittest.expectedFailure()  
          def test_windows_support(self):  
            # windows specific testing code  
            pass
        def test_divide(self):
            """Test method divide(a, b)"""
            self.skipTest('Do not run this.')
            print "divide"
            self.assertEqual(2, divide(6, 3))
            self.assertEqual(2.5, divide(5, 2))

    忽略测试类:

    @unittest.skip("showing class skipping")  
    class MySkippedTestCase(unittest.TestCase):  
        def test_not_run(self):  
            pass

    用例结果断言:

    assertEqual(a, b) a == b
    assertNotEqual(a, b) a != b
    assertTrue(x) bool(x) is True
    assertFalse(x) bool(x) is False
    assertIs(a, b) a is b
    assertIsNot(a, b) a is not b
    assertIsNone(x) x is None
    assertIsNotNone(x) x is not None
    assertIn(a, b) a in b
    assertNotIn(a, b) a not in b
    assertIsInstance(a, b) isinstance(a, b)
    assertNotIsInstance(a, b) not isinstance(a, b)
    assertAlmostEqual(a, b) round(a-b, 7) == 0
    assertNotAlmostEqual(a, b) round(a-b, 7) != 0
    assertGreater(a, b) a > b
    assertGreaterEqual(a, b) a >= b
    assertLess(a, b) a < b
    assertLessEqual(a, b) a <= b
    assertRegexpMatches(s, r) r.search(s)
    assertNotRegexpMatches(s, r) not r.search(s)
    assertItemsEqual(a, b) sorted(a) == sorted(b) and works with unhashable objs
     
       
    '''
    unittest条件断言
    tester: cc
    此文仅做翻译只用,不介绍具体使用
    
    
    '''
    Skiptest()  # 在测试中引发此异常以跳过该异常。
    _ShouldStop()  # 停止测试
    _UnexpectedSuccess()  # 测试本来应该是失败的,但是没有失败
    Skip()  # 无条件跳过测试。
    skipIf(condition, reason)  # 条件为真时跳过测试
    skipUnless(condition, reason)  # 条件为假时跳过测试
    expectedFailure(test_item)  # 标记该测试预期就是失败,如果运行失败时,不算作失败用例。
    _is_subtype(expected, basetype)  # 判断类型是否符合预期,暂时不知道干什么用的
    addTypeEqualityFunc(typeobj, function) # 为自定义检查类提供检查方法
    addCleanup( function , *args , **kwargs ) #添加针对每个测试用例执行完tearDown()方法之后的清理方法,添加进去的函数按照后进先出(LIFO)的顺序执行,当然,如果setUp()方法执行失败,那么不会执行tearDown()方法,自然也不会执行addCleanup()里添加的函数。
    setUp()#在执行每个测试用例之前被执行,任何异常(除了unittest.SkipTest和AssertionError异常以外)都会当做是error而不是failure,且会终止当前测试用例的执行。
    tearDown()#执行了setUp()方法后,不论测试用例执行是否成功,都执行tearDown()方法。如果tearDown()的代码有异常(除了unittest.SkipTest和AssertionError异常以外),会多算一个error。
    setUpClass( cls )与tearDownClass( cls )#测试用例们被执行前、后执行的方法,定义时必须加上classmethod装饰符
    countTestCases()#返回测试用例的个数,对于TestCase实例来说,这个返回值一直是1.
    defaultTestResult()#如果在run()方法中未提供result参数,该函数返回一个包含本用例测试结果的TestResult对象。
    shortDescription()#返回测试用例的描述,即函数的docstring,如果没有,返回None。可以用于测试结果输出中描述测试内容。
    id()#返回测试用例的编号,通常是如下格式:模块名.类名.函数名。可以用于测试结果的输出。
    subTest( msg=_subtest_msg_sentinel, **params)#返回一个上下文管理器,它将返回由可选消息和关键字参数标识的子测试中的封闭代码块。子测试中的失败标志着测试用例失败,但在封闭块结束时恢复执行,允许执行进一步的测试代码。
    run( result =None)#运行一个测试用例,将测试结果收集到result变量中,测试结果不返回给调用者。如果result参数的值为None,则测试结果在下面提到的defaultTestResult()方法的返回值中
    doCleanups()#无条件强制调用addCleanup()添加的函数,适用于setUp()方法执行失败但是需要执行清理函数的场景,或者希望在tearDown()方法之前执行这些清理函数。
    debug()#与run方法将测试结果存储到result变量中不同,debug方法运行测试用例将异常信息上报给调用者。
    fail( msg =None)#无条件声明一个测试用例失败,msg是失败信息。
    assertFalse( expr, msg=None) #检查表达式是否为假
    assertTrue( expr, msg=None) #检查表达式是否为真
    assertAlmostEqual与assertNotAlmostEqual(, first, second, places=None, msg=None,delta=None) #判断两个值是否约等于或者不约等于,places表示小数点后精确的位数
    assertSequenceEqual(seq1, seq2, msg=None, seq_type=None) #有序序列的相等断言,如元组、列表
    assertListEqual( list1, list2, msg=None) #列表相等的特定断言
    assertTupleEqual(tuple1, tuple2, msg=None) #元组相等的特定断言
    assertSetEqual( set1, set2, msg=None) #集合相等的特定断言
    assertIn与assertNotIn( member, container, msg=None) #判断a 是否存在b中
    assertIs与assertIsNot( expr1, expr2, msg=None) #判断a是不是b
    assertDictEqual( d1, d2, msg=None) #检查两个字典是否相等
    assertDictContainsSubset( subset, dictionary, msg=None) #检查字典是否是子集的超集。
    assertCountEqual(first, second, msg=None) #判断两个无序列表内所出现的内容是否相等
    assertMultiLineEqual( first, second, msg=None) #断言两个多行字符串相等
    assertLess( a, b, msg=None) #断言a<b
    assertLessEqual( a, b, msg=None) #断言a<=b
    assertGreater( a, b, msg=None) #断言a>b
    assertGreaterEqual(a, b, msg=None) #断言a>=b
    assertIsNone与assertIsNotNone( obj, msg=None) #判断obj是否为空
    assertIsInstance(a, b)与assertNotIsInstance(a, b)# 与assertTrue相同,其中的类型b,既可以是一个类型,也可以是类型组成的元组。
    assertRaisesRegex( expected_exception, expected_regex,*args, **kwargs)#断言在引发异常中的消息与正则表达式匹配。
    assertWarnsRegex( expected_warning, expected_regex,*args, **kwargs)#断言触发警告中的消息与ReGEXP匹配。基本功能类似于AdvestWr.NS.()只有消息与正则表达式匹配的警告。被认为是成功的匹配
    assertRegex与assertNotRegex(text, expected_regex, msg=None) #判断文本与正则表达式是否匹配
    shortDescription()#返回测试用例的描述,即函数的docstring,如果没有,返回None。可以用于测试结果输出中描述测试内容。

    输出测试HTML报告 :HTMLTestRunner

    修改执行测试文件:
    # -*- coding: utf-8 -*-
    
    import unittest
    from test_mathfunc import TestMathFunc
    from HTMLTestRunner import HTMLTestRunner #引入HTMLtestrunner
    
    if __name__ == '__main__':
        suite = unittest.TestSuite() 
        suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc)) # 执行testmathfunc
    
        with open('HTMLReport.html', 'w') as f: 
            runner = HTMLTestRunner(stream=f, #写入HTML文件
                                    title='MathFunc Test Report', #运行状况
                                    description='generated by HTMLTestRunner.', #执行结果
                                    verbosity=2
                                    )
            runner.run(suite)

    另一种输出方式:

    # -*- coding: utf-8 -*-
    import unittest,time
    from HTMLTestRunner import HTMLTestRunner
    from email.mime.text import MIMEText
    from email.header import Header
    import smtplib
    test_dir='./test_jb/' #目录路径
    discover=unittest.defaultTestLoader.discover(test_dir,pattern='test_*.py') #查找当前目录下的所有以test_开头的文件,并执行
    
    if __name__=='__main__':
        now=time.strftime('%Y-%m-%d %H_%M_%S')#当前日期
        filename=test_dir+now+'result.html' #名称后缀
        fp=open(filename,'wb') #写入内容
        runner=HTMLTestRunner(stream=fp,title='测试报告',description='用例执行情况') #执行测试方式
        runner.run(discover)# 执行测试
        fp.close() #关闭测试

    原文地址:https://blog.csdn.net/huilan_same/article/details/52944782

     
     
     
     
     
     
  • 相关阅读:
    HTML5 学习04—— MathML数学标记
    HTML5 学习03——内联 SVG
    HTML5 学习02——新元素:canvas
    HTML5 学习01——浏览器问题、新元素
    HTML 回顾整理
    jQuery 学习05——AJAX:定义、load()方法、get()/post()方法
    jQuery 学习04——遍历:定义、向上、向下、同级、过滤
    jQuery 学习03——HTML:捕获、设置、添加元素、删除元素、CSS类、CSS()方法、尺寸
    UIDatePicker
    UIPikerView的属性
  • 原文地址:https://www.cnblogs.com/yc-c/p/9155888.html
Copyright © 2011-2022 走看看