• python单元测试框架—unittest


    目录

    unittest核心工作原理

    unittest示例

    示例1:简单示例

    示例2:setUpClass()和tearDownClass()

    示例3:通过在测试用例方法名中添加数字test_N指定执行顺序

    示例4:skip跳过测试用例执行的3种方式

    示例5:组织TestSuite

    示例6:assert断言

    断言方法说明

    示例7:输出HTML报告

    示例8:第一个webDriver测试

    示例9:ddt数据驱动


    unittest核心工作原理

    转载于文章Python必会的单元测试框架 —— 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

    一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite中时也有四个测试用例。

    到这里整个流程就清楚了:

    写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。这里加个说明,在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果(你可能听说过HTMLTestRunner,是的,通过它可以将结果输出到HTML中,生成漂亮的报告,它跟TextTestRunner是一样的,从名字就能看出来)。

    unittest示例

    示例1:简单示例

    1. #encoding=utf-8
    2. import unittest
    3. import random
    4. class TestSequenceFunctions(unittest.TestCase):
    5. def setUp(self):
    6. # 初始化一个递增序列
    7. self.seq = list(range(10))
    8. print ("setup completed!")
    9. def test_run(self):
    10. # 从序列seq中随机选取一个元素
    11. element = random.choice(self.seq)
    12. # 验证随机元素确实属于列表中
    13. self.assertTrue(element in self.seq)
    14. def test_sth(self):
    15. assert 1==2
    16. def tearDown(self):
    17. print ("tearDown completed")
    18. class TestDictValueFormatFunctions(unittest.TestCase):
    19. def setUp(self):
    20. self.seq = list(range(10))
    21. print("setup is ready!")
    22. def test_shuffle(self):
    23. # 随机打乱原seq的顺序
    24. random.shuffle(self.seq)
    25. self.seq.sort()
    26. self.assertEqual(self.seq, list(range(10)))
    27. # 验证执行函数时抛出了TypeError异常
    28. self.assertRaises(TypeError, random.shuffle, (1, 2, 3))
    29. def tearDown(self):
    30. print ("tearDown is Done!")
    31. if __name__ == '__main__':
    32. unittest.main()

    执行结果: 

    1. setup is ready!
    2. tearDown is Done!
    3. .setup completed!
    4. tearDown completed
    5. .setup completed!
    6. tearDown completed
    7. F
    8. ======================================================================
    9. FAIL: test_sth (__main__.TestSequenceFunctions)
    10. ----------------------------------------------------------------------
    11. Traceback (most recent call last):
    12. File "F:\unittest\e1_unittest_demo.py", line 17, in test_sth
    13. assert 1==2
    14. AssertionError
    15. ----------------------------------------------------------------------
    16. Ran 3 tests in 0.027s
    17. FAILED (failures=1)

    说明:

    • 可以看到一共运行了3个测试用例,2个成功,1个失败,并给出失败原因:1==2
    • 每一个用例执行的结果的标识,成功是 .,失败是 F,出错是 E,跳过是 S
    • setUp()和tearDown()分别执行了3次,在每个测试用例执行前后分别执行了setUp和tearDown方法
    • 每个测试方法均以 test 开头,否则是不被unittest识别的
    • 可以看到测试的执行跟方法写的位置顺序没有关系,测试用例的默认执行顺序是根据用例名的字母顺序来的,先执行了TestDictValueFormatFunctions类中的test_shuffle,然后执行了TestSequenceFunctions类中的test_run,最后执行了TestSequenceFunctions中类的test_sth

    示例2:setUpClass()和tearDownClass()

    1. #encoding=utf-8
    2. import unittest
    3. # 被测试类
    4. class myclass(object):
    5. @classmethod
    6. def sum(self, a, b):
    7. return a + b #将两个传入参数进行相加操作
    8. @classmethod
    9. def sub(self, a, b):
    10. return a - b #将两个传入参数进行相减操作
    11. class mytest(unittest.TestCase):
    12. @classmethod
    13. def setUpClass(cls):#每个测试类的setUpClass方法,只会执行一次
    14. "初始化类固件"
    15. print ( "----setUpClass")
    16. @classmethod
    17. def tearDownClass(cls):#每个测试类的tearDownClass方法,只会执行一次
    18. "重构类固件"
    19. print ( "----tearDownClass")
    20. # 初始化工作
    21. def setUp(self):#每个测试方法均会执行一次
    22. self.a = 3
    23. self.b = 1
    24. print ( "--setUp")
    25. # 退出清理工作
    26. def tearDown(self):#每个测试方法均会执行一次
    27. print ( "--tearDown")
    28. # 具体的测试用例,一定要以test开头
    29. def testsum(self):
    30. # 断言两数之和的结果是否是4
    31. self.assertEqual(myclass.sum(self.a, self.b), 4, 'test sum fail')
    32. def testsub(self):
    33. # 断言两数之差的结果是否是2
    34. self.assertEqual(myclass.sub(self.a, self.b), 2, 'test sub fail')
    35. if __name__ == '__main__':
    36. unittest.main() # 启动单元测试

    执行结果:

    1. ----setUpClass
    2. --setUp
    3. --tearDown
    4. .--setUp
    5. --tearDown
    6. .----tearDownClass
    7. ----------------------------------------------------------------------
    8. Ran 2 tests in 0.011s
    9. OK

    说明:

    setUpClass()tearDownClass()分别在每个测试类执行前后各执行一次(不管这个测试类中有多少个测试方法,它们都仅执行一次);而setUp()和tearDown()分别在每个测试方法执行前后各执行一次。

    示例3:通过在测试用例方法名中添加数字test_N指定执行顺序

    Calc.py

    1. # coding=utf-8
    2. class Calc(object):
    3. def add(self, x, y, *d):
    4. # 加法计算
    5. result = x + y
    6. for i in d:
    7. result += i
    8. return result
    9. def sub(self, x, y, *d):
    10. # 减法计算
    11. result = x - y
    12. for i in d:
    13. result -= i
    14. return result
    15. @classmethod
    16. def mul(cls, x, y, *d):
    17. # 乘法计算
    18. result = x * y
    19. for i in d:
    20. result *= i
    21. return result
    22. @staticmethod
    23. def div(x, y, *d):
    24. # 除法计算
    25. if y != 0:
    26. result = x / y
    27. else:
    28. raise ZeroDivisionError
    29. return -1
    30. for i in d:
    31. if i != 0:
    32. result /= i
    33. else:
    34. raise ZeroDivisionError
    35. return -1
    36. return result
    37. if __name__=="__main__":
    38. c=Calc()
    39. print (c.add(1,2,3,4))
    40. #print c.add(1,2,[3,4],5,a=3))
    41. print (c.sub(1,2,3,4))
    42. print (c.mul(2,3,4))
    43. print (c.div(10,5,1))
    44. print (c.div(1,0,0))
    45. print (c.div(1,1,0))
    46. print (Calc.mul(1,2,3,4))
    47. print (Calc.div(100,10,5,1))

    e3_Test_Calc_by_specific_order.py

    1. #encoding=utf-8
    2. import unittest
    3. from Calc import Calc
    4. class MyTest(unittest.TestCase):
    5. @classmethod
    6. def setUpClass(self):
    7. print ("单元测试前,创建Calc类的实例")
    8. self.c = Calc()
    9. def test_3div(self):
    10. print ("run div()")
    11. self.assertEqual(Calc.div(8, 2, 4), 1, 'test div fail')
    12. # 具体的测试用例,一定要以test开头,执行顺序按照字母顺序开头
    13. def test_0add(self):
    14. print ("run add()")
    15. self.assertEqual(self.c.add(1, 2, 12), 15, 'test add fail')
    16. def test_1sub(self):
    17. print ("run sub()")
    18. self.assertEqual(self.c.sub(2, 1, 3), -2, 'test sub fail')
    19. def test_2mul(self):
    20. print ("run mul()")
    21. self.assertEqual(Calc.mul(2, 3, 5), 30, 'test mul fail')
    22. if __name__ == '__main__':
    23. unittest.main()# 启动单元测试

    执行结果:

    1. 单元测试前,创建Calc类的实例
    2. run add()
    3. .run sub()
    4. .run mul()
    5. .run div()
    6. .
    7. ----------------------------------------------------------------------
    8. Ran 4 tests in 0.020s
    9. OK

    可以发现执行顺序变成我们指定的0add-1sub-2mul-3div顺序

    示例4:skip跳过测试用例执行的3种方式

    1. # coding=utf-8
    2. import random
    3. import unittest
    4. import sys
    5. class TestSequenceFunctions(unittest.TestCase):
    6. a = 6
    7. def setUp(self):
    8. self.seq = list(range(10))
    9. @unittest.skip("skipping") # 无条件忽略该测试方法
    10. def test_shuffle(self):
    11. random.shuffle(self.seq)
    12. self.seq.sort()
    13. self.assertEqual(self.seq, list(range(10)))
    14. self.assertRaises(TypeError, random.shuffle, (1, 2, 3))
    15. # 如果变量a > 5,则忽略该测试方法
    16. @unittest.skipIf(a > 5, "condition is not satisfied!")
    17. def test_choice(self):
    18. element = random.choice(self.seq)
    19. self.assertTrue(element in self.seq)
    20. # 除非执行测试用例的平台是Linux平台,否则忽略该测试方法 win32是windows
    21. @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
    22. def test_sample(self):
    23. with self.assertRaises(ValueError):
    24. random.sample(self.seq, 20)
    25. for element in random.sample(self.seq, 5):
    26. self.assertTrue(element in self.seq)
    27. if __name__ == '__main__':
    28. # unittest.main()
    29. suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)# 加载TestSequenceFunctions测试类
    30. suite = unittest.TestSuite(suite)#
    31. unittest.TextTestRunner(verbosity = 2).run(suite)

    执行结果:

    1. test_choice (__main__.TestSequenceFunctions) ... skipped 'condition is not satisfied!'
    2. test_sample (__main__.TestSequenceFunctions) ... skipped 'requires Linux'
    3. test_shuffle (__main__.TestSequenceFunctions) ... skipped 'skipping'
    4. ----------------------------------------------------------------------
    5. Ran 3 tests in 0.001s
    6. OK (skipped=3)

    可以看到上面3个测试方法都被跳过。并打印了自定义的跳过原因信息

    • skip装饰器一共有三个 unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。
    • verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果,即没有. F S E这种结果输出;如果设为 2,则输出详细的执行结果

    示例5:组织TestSuite

    testCalc.py

    1. #encoding=utf-8
    2. import unittest
    3. import random
    4. from Calc import Calc
    5. class TestCalcFunctions(unittest.TestCase):
    6. def setUp(self):
    7. self.c=Calc()
    8. print ("setup completed!")
    9. def test_sum(self):
    10. """TestCalcFunctions.test_sum()"""
    11. self.assertTrue(self.c.add(1,2,3,4)==10)
    12. def test_sub(self):
    13. self.assertTrue(self.c.sub(100,20,30,40)==10)
    14. def test_mul(self):
    15. self.assertTrue(self.c.mul(1,2,3,40)==240)
    16. def test_div(self):
    17. self.assertTrue(self.c.div(100,10,2)==5)
    18. def tearDown(self):
    19. print ("test completed!")
    20. def tearDown(self):
    21. print ("tearDown completed")
    22. if __name__ == '__main__':
    23. unittest.main()

    e5_unittest_suite.py

    1. #encoding=utf-8
    2. import random
    3. import unittest
    4. from TestCalc import TestCalcFunctions
    5. class TestSequenceFunctions(unittest.TestCase):
    6. def setUp(self):
    7. self.seq = list(range(10))
    8. def tearDown(self):
    9. pass
    10. def test_choice(self):
    11. """TestSequenceFunctions.test_choice()"""
    12. # 从序列seq中随机选取一个元素
    13. element = random.choice(self.seq)
    14. # 验证随机元素确实属于列表中
    15. self.assertTrue(element in self.seq)
    16. def test_sample(self):
    17. """TestSequenceFunctions.test_sample()"""
    18. # 验证执行的语句是否抛出了异常
    19. with self.assertRaises(ValueError):
    20. random.sample(self.seq, 20)
    21. for element in random.sample(self.seq, 5):
    22. self.assertTrue(element in self.seq)
    23. class TestDictValueFormatFunctions(unittest.TestCase):
    24. def setUp(self):
    25. self.seq = list(range(10))
    26. def tearDown(self):
    27. pass
    28. def test_shuffle(self):
    29. """TestDictValueFormatFunctions.test_shuffle()"""
    30. # 随机打乱原seq的顺序
    31. random.shuffle(self.seq)
    32. self.seq.sort()
    33. self.assertEqual(self.seq, list(range(10)))
    34. # 验证执行函数时抛出了TypeError异常
    35. self.assertRaises(TypeError, random.shuffle, (1, 2, 3))
    36. if __name__ == '__main__':
    37. # 根据给定的测试类,获取其中的所有以“test”开头的测试方法,并返回一个测试套件
    38. suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
    39. suite2 = unittest.TestLoader().loadTestsFromTestCase(TestDictValueFormatFunctions)
    40. suite3 = unittest.TestLoader().loadTestsFromTestCase(TestCalcFunctions)
    41. # 加载当前目录下所有有效的测试模块(以test开头的文件),“.”表示当前目录
    42. # testSuite = unittest.TestLoader().discover('.') #.可以改为绝对路径
    43. # 将多个测试类加载到测试套件中
    44. suite = unittest.TestSuite([suite2, suite1,suite3]) #通过调整suit2和suite1的顺序,可以设定执行顺序
    45. # 设置verbosity = 2,可以打印出更详细的执行信息
    46. unittest.TextTestRunner(verbosity = 2).run(suite)

    执行结果:

    1. test_shuffle (__main__.TestDictValueFormatFunctions)
    2. TestDictValueFormatFunctions.test_shuffle() ... ok
    3. test_choice (__main__.TestSequenceFunctions)
    4. TestSequenceFunctions.test_choice() ... ok
    5. test_sample (__main__.TestSequenceFunctions)
    6. TestSequenceFunctions.test_sample() ... ok
    7. test_div (TestCalc.TestCalcFunctions) ... setup completed!
    8. tearDown completed
    9. ok
    10. test_mul (TestCalc.TestCalcFunctions) ... setup completed!
    11. tearDown completed
    12. ok
    13. test_sub (TestCalc.TestCalcFunctions) ... setup completed!
    14. tearDown completed
    15. ok
    16. test_sum (TestCalc.TestCalcFunctions)
    17. TestCalcFunctions.test_sum() ... setup completed!
    18. tearDown completed
    19. ok
    20. ----------------------------------------------------------------------
    21. Ran 7 tests in 0.011s
    22. OK

    说明:

    • 我们添加到TestSuite中的case是会按照添加的顺序执行的。通过调整suite2和suite1的顺序,指定了执行的顺序。先执行的是TestDictValueFormatFunctions.test_shuffle(),然后依次执行的TestSequenceFunctions类中的test_choice()和test_sample(),最后执行的TestCalcFunctions类中的test_div()、test_mul()、test_sub()、test_sum()
    • 在测试方法下加代码示例中的”“”Doc String”“”,在用例执行时,会将该字符串作为此用例的描述并输出,加合适的注释能够使输出的测试报告更加便于阅读

    示例6:assert断言

    1. #encoding=utf-8
    2. import unittest
    3. import random
    4. # 被测试类
    5. class MyClass(object):
    6. @classmethod
    7. def sum(self, a, b):
    8. return a + b
    9. @classmethod
    10. def div(self, a, b):
    11. return a / b
    12. @classmethod
    13. def retrun_None(self):
    14. return None
    15. # 单元测试类
    16. class MyTest(unittest.TestCase):
    17. # assertEqual()方法实例
    18. def test_assertEqual(self):
    19. # 断言两数之和的结果
    20. a, b = 1, 2
    21. sum = 4
    22. self.assertEqual(a + b, sum, '断言失败,%s + %s != %s' %(a, b, sum))
    23. # assertNotEqual()方法实例
    24. def test_assertNotEqual(self):
    25. # 断言两数之差的结果
    26. a, b = 5, 2
    27. res = 1
    28. self.assertNotEqual(a - b, res, '断言失败,%s - %s != %s' %(a, b, res))
    29. # assertTrue()方法实例
    30. def test_assertTrue(self):
    31. # 断言表达式的为真
    32. self.assertTrue(1 == 1, "表达式为假")
    33. # assertFalse()方法实例
    34. def test_assertFalse(self):
    35. # 断言表达式为假
    36. self.assertFalse(3 == 2, "表达式为真")
    37. # assertIs()方法实例
    38. def test_assertIs(self):
    39. # 断言两变量类型属于同一对象
    40. a = 12
    41. b = a
    42. self.assertIs(a, b, "%s与%s不属于同一对象" %(a, b))
    43. # test_assertIsNot()方法实例
    44. def test_assertIsNot(self):
    45. # 断言两变量类型不属于同一对象
    46. a = 12
    47. b = "test"
    48. self.assertIsNot(a, b, "%s与%s属于同一对象" %(a, b))
    49. # assertIsNone()方法实例
    50. def test_assertIsNone(self):
    51. # 断言表达式结果为None
    52. result = MyClass.retrun_None()
    53. self.assertIsNone(result, "not is None")
    54. # assertIsNotNone()方法实例
    55. def test_assertIsNotNone(self):
    56. # 断言表达式结果不为None
    57. result = MyClass.sum(2, 5)
    58. self.assertIsNotNone(result, "is None")
    59. # assertIn()方法实例
    60. def test_assertIn(self):
    61. # 断言对象A是否包含在对象B中
    62. strA = "this is a test"
    63. strB = "is"
    64. self.assertIn(strB, strA, "%s不包含在%s中" %(strB, strA))
    65. # assertNotIn()方法实例
    66. def test_assertNotIn(self):
    67. # 断言对象A不包含在对象B中
    68. strA = "this is a test"
    69. strB = "Selenium"
    70. self.assertNotIn(strB, strA, "%s包含在%s中" %(strB, strA))
    71. # assertIsInstance()方法实例
    72. def test_assertIsInstance(self):
    73. # 测试对象x的类型是否是指定的类型y
    74. x = MyClass
    75. y = object
    76. self.assertIsInstance(x, y, "%s的类型不是%s" %(x, y))
    77. # assertNotIsInstance()方法实例
    78. def test_assertNotIsInstance(self):
    79. # 测试对象A的类型不是指定的类型
    80. a = 123
    81. b = str
    82. self.assertNotIsInstance(a, b, "%s的类型是%s" %(a, b))
    83. # assertRaises()方法实例
    84. def test_assertRaises(self):
    85. # 测试抛出的指定的异常类型
    86. # assertRaises(exception)
    87. # with self.assertRaises(TypeError) as cm:
    88. # random.sample([1,2,3,4,5], "j")
    89. # 打印详细的异常信息
    90. # print("===", cm.exception)
    91. # assertRaises(exception, callable, *args, **kwds)
    92. self.assertRaises(ZeroDivisionError, MyClass.div, 3, 0)
    93. # assertRaisesRegex()方法实例
    94. def test_assertRaisesRegex(self):
    95. # 测试抛出的指定异常类型,并用正则表达式具体验证
    96. # assertRaisesRegexp(exception, regexp)
    97. # with self.assertRaisesRegex(ValueError, 'literal') as ar:
    98. # int("xyz")
    99. # 打印详细的异常信息
    100. # print(ar.exception)
    101. # 打印正则表达式
    102. # print("re:",ar.expected_regex)
    103. # assertRaisesRegexp(exception, regexp, callable, *args, **kwds)
    104. # try:
    105. self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')
    106. # except AssertionError as e:
    107. # print (e)
    108. if __name__ == '__main__':
    109. # 执行单元测试
    110. unittest.main(verbosity=2)

    执行结果:

    1. test_assertEqual (__main__.MyTest) ... FAIL
    2. test_assertFalse (__main__.MyTest) ... ok
    3. test_assertIn (__main__.MyTest) ... ok
    4. test_assertIs (__main__.MyTest) ... ok
    5. test_assertIsInstance (__main__.MyTest) ... ok
    6. test_assertIsNone (__main__.MyTest) ... ok
    7. test_assertIsNot (__main__.MyTest) ... ok
    8. test_assertIsNotNone (__main__.MyTest) ... ok
    9. test_assertNotEqual (__main__.MyTest) ... ok
    10. test_assertNotIn (__main__.MyTest) ... ok
    11. test_assertNotIsInstance (__main__.MyTest) ... ok
    12. test_assertRaises (__main__.MyTest) ... ok
    13. test_assertRaisesRegex (__main__.MyTest) ... ok
    14. test_assertTrue (__main__.MyTest) ... ok
    15. ======================================================================
    16. FAIL: test_assertEqual (__main__.MyTest)
    17. ----------------------------------------------------------------------
    18. Traceback (most recent call last):
    19. File "F:\unittest\e6_unittest_assert-2.py", line 26, in test_assertEqual
    20. self.assertEqual(a + b, sum, '断言失败,%s + %s != %s' %(a, b, sum))
    21. AssertionError: 3 != 4 : 断言失败,1 + 2 != 4
    22. ----------------------------------------------------------------------
    23. Ran 14 tests in 0.013s
    24. FAILED (failures=1)

    断言方法说明

    断言方法断言描述备注
    assertEqual(arg1, arg2, msg=None)验证arg1=arg2,不等则failarg1 = arg2
    assertNotEqual(arg1, arg2, msg=None)验证arg1 != arg2, 相等则failarg1 != arg2
    assertTrue(expr, msg=None)验证expr是true,如果为false,则failbool(expr) IS true
    assertFalse(expr,msg=None)验证expr是false,如果为true,则failbool(expr) IS false
    assertIs(arg1, arg2, msg=None)验证arg1、arg2是同一个对象,不是则failarg1 is arg2
    assertIsNot(arg1, arg2, msg=None)验证arg1、arg2不是同一个对象,是则failarg1 not is arg2
    assertIsNone(expr, msg=None)验证expr是None,不是则failexpr is one
    assertIsNotNone(expr, msg=None)验证expr不是None,是则failexpr not is one
    assertIn(arg1, arg2, msg=None)验证arg1是arg2的子串,不是则failarg1 in arg2
    assertNotIn(arg1, arg2, msg=None)验证arg1不是arg2的子串,是则failarg1 not in arg2
    assertIsInstance(obj, cls, msg=None)验证obj是cls的实例,不是则failIsInstance(obj,cls)
    assertNotIsInstance(obj, cls, msg=None)验证obj不是cls的实例,是则failnot IsInstance(obj,cls)

    更多方法说明请参考python的unittest单元测试框架断言整理汇总

    示例7:输出HTML报告

    HTMLTestRunner是一个第三方的unittest HTML报告库,首先我们下载HTMLTestRunner.py,并放到当前目录下,或者你的’C:\Python310\Lib’下,就可以导入运行了。

    下载地址:

    官方原版:HTMLTestRunner - tungwaiyip's software

    1. # coding=utf-8
    2. import unittest
    3. import HTMLTestRunner
    4. import math
    5. class Calc(object):
    6. def add(self, x, y, *d):
    7. # 加法计算
    8. result = x + y
    9. for i in d:
    10. result += i
    11. return result
    12. def sub(self, x, y, *d):
    13. # 减法计算
    14. result = x - y
    15. for i in d:
    16. result -= i
    17. return result
    18. class SuiteTestCalc(unittest.TestCase):
    19. def setUp(self):
    20. self.c = Calc()
    21. @unittest.skip("skipping")
    22. def test_Sub(self):
    23. print ("sub")
    24. self.assertEqual(self.c.sub(100, 34, 6), 61, u'求差结果错误!')
    25. def testAdd(self):
    26. print ("add")
    27. self.assertEqual(self.c.add(1, 32, 56), 89, u'求和结果错误!')
    28. class SuiteTestPow(unittest.TestCase):
    29. def setUp(self):
    30. self.seq = list(range(10))
    31. # @unittest.skipIf()
    32. def test_Pow(self):
    33. print ("Pow")
    34. self.assertEqual(pow(6, 3), 2161, u'求幂结果错误!')
    35. def test_hasattr(self):
    36. print ("hasattr")
    37. # 检测math模块是否存在pow属性
    38. self.assertTrue(hasattr(math, 'pow1'), u"检测的属性不存在!")
    39. if __name__ == "__main__":
    40. suite1 = unittest.TestLoader().loadTestsFromTestCase(SuiteTestCalc)
    41. suite2 = unittest.TestLoader().loadTestsFromTestCase(SuiteTestPow)
    42. suite = unittest.TestSuite([suite1, suite2])
    43. #unittest.TextTestRunner(verbosity=2).run(suite)
    44. filename = "test.html" # 定义个报告存放路径,支持相对路径。
    45. # 以二进制方式打开文件,准备写
    46. fp = open(filename, 'wb')
    47. # 使用HTMLTestRunner配置参数,输出报告路径、报告标题、描述,均可以配
    48. runner = HTMLTestRunner.HTMLTestRunner(stream = fp,
    49. title = '测试报告', description = '测试报告内容')
    50. # 运行测试集合
    51. runner.run(suite)
    52. fp.close()

    执行结果:

    示例8:第一个webDriver测试

    1. #encoding=utf-8
    2. import unittest
    3. from selenium import webdriver
    4. from selenium.webdriver.common.by import By
    5. from selenium.webdriver.common.keys import Keys
    6. import time
    7. import HTMLTestRunner
    8. class GloryRoad(unittest.TestCase):
    9. def setUp(self):
    10. # 启动Firefox浏览器
    11. self.driver = webdriver.Chrome(executable_path = r"E:\Programs\Driver\chromedriver")
    12. def testSoGou(self):
    13. # 访问搜狗首页
    14. self.driver.get("http://sogou.com")
    15. # 清空搜索输入框默认内容
    16. self.driver.find_element(By.ID,"query").clear()
    17. # 在搜索输入框中输入“光荣之路自动化测试”
    18. self.driver.find_element(By.ID,"query").send_keys("WebDriver实战宝典")
    19. # 单击“搜索”按钮
    20. self.driver.find_element(By.ID,"stb").click()
    21. # 等待3秒
    22. time.sleep(3)
    23. assert "吴晓华" in self.driver.page_source, "页面中不存在要寻找的关键字!".encode("gbk")
    24. def testBing(self):
    25. # 访问bing首页
    26. self.driver.get("http://cn.bing.com")
    27. # 清空搜索输入框默认内容
    28. self.driver.find_element(By.ID, "sb_form_q").clear()
    29. # 在搜索输入框中输入“光荣之路自动化测试”
    30. self.driver.find_element(By.ID, "sb_form_q").send_keys("WebDriver实战宝典")
    31. # 单击“搜索”按钮,目前已经不能点击该label
    32. # self.driver.find_element(By.ID, "sb_form_go").click()
    33. # 按"回车"搜索
    34. self.driver.find_element(By.ID, "sb_form_q").send_keys(Keys.ENTER)
    35. # 等待3秒
    36. time.sleep(3)
    37. assert "吴晓华" in self.driver.page_source, "页面中不存在要寻找的关键字!".encode("gbk")
    38. def tearDown(self):
    39. # 退出浏览器
    40. self.driver.quit()
    41. if __name__ == '__main__':
    42. # unittest.main()
    43. suite = unittest.TestLoader().loadTestsFromTestCase(GloryRoad)
    44. suite = unittest.TestSuite(suite)
    45. #unittest.TextTestRunner(verbosity=2).run(suite)
    46. filename = "e9_test.html" # 定义个报告存放路径,支持相对路径。
    47. # 以二进制方式打开文件,准备写
    48. fp = open(filename, 'wb')
    49. # 使用HTMLTestRunner配置参数,输出报告路径、报告标题、描述,均可以配
    50. runner = HTMLTestRunner.HTMLTestRunner(stream = fp,
    51. title = '测试报告', description = '测试报告内容')
    52. # 运行测试集合
    53. runner.run(suite)
    54. fp.close()

    执行结果:

    示例9:ddt数据驱动

     安装:

    py -3 -m pip install ddt

    1. import unittest
    2. import ddt
    3. @ddt.ddt
    4. class Praddt(unittest.TestCase):
    5. def setUp(self):
    6. print("my test start!")
    7. def tearDown(self):
    8. print("my test complete!")
    9. @ddt.data(["wulaoshi","pass123", "success"],
    10. ["lilaoshi","pwd123", "success"],
    11. ["zhanglaoshi", "1qaz", "ERROR"]) #一个方括号是一组测试数据
    12. @ddt.unpack
    13. def test_ddt(self, user, passwd, expect_value):
    14. login_info = {"wulaoshi":"pass123","lilaoshi":"pwd123"}
    15. print(user,passwd,expect_value)
    16. if user in login_info:
    17. if passwd == login_info[user]:
    18. result = "success"
    19. else:
    20. result = "ERROR"
    21. else:
    22. result = "ERROR"
    23. assert result==expect_value
    24. if __name__ == '__main__':
    25. # 执行单元测试
    26. unittest.main()

    执行结果: 

    1. my test start!
    2. wulaoshi pass123 success
    3. my test complete!
    4. .my test start!
    5. lilaoshi pwd123 success
    6. my test complete!
    7. .my test start!
    8. zhanglaoshi 1qaz ERROR
    9. my test complete!
    10. .
    11. ----------------------------------------------------------------------
    12. Ran 3 tests in 0.026s
    13. OK

     

  • 相关阅读:
    Redis 源码简洁剖析 12 - 一条命令的处理过程
    如何在windows下安装ray(install Ray under windows)
    Hadoop面试问题总结
    Spring通过配置文件管理Bean对象
    NL2SQL技术方案系列(1):NL2API、NL2SQL技术路径选择;LLM选型与Prompt工程技巧,揭秘项目落地优化之道
    信创操作系统--麒麟Kylin桌面操作系统 (项目十二 使用Systemd管理系统服务)
    5.7w字?GitHub标星120K的Java面试知识点总结,真就物超所值了
    【数据结构】—— 队列基础知识以及数组模拟队列的分析、演示及优化
    async异步函数
    这些专业配音软件你值得拥有
  • 原文地址:https://blog.csdn.net/qq_22895113/article/details/126289082