单元测试框架unittest
Posted hqq2019-10
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单元测试框架unittest相关的知识,希望对你有一定的参考价值。
1、什么是单元测试
测试函数/方法或者一段代码,用于检验被测代码的一个很小的、很明确的功能是否正确,通常是开发做。
2、单元测试框架
1)结构
测试基本setup方法:第一个测试开始之前只执行一次
多个类
类:
类setup方法:在当前类的第一个测试方法调用前执行,只执行一次
setup方法:在执行测试方法前的一些环境或者数据相关的准备
测试的方法:每个测试方法执行前,都会执行setup方法,然后执行teardown方法
teardown方法:在执行方法后的一些环境或者数据相关的清理
类teardown方法:在当前类的最后一个测试方法调用后执行,只执行一次
测试级别teardown方法:所有的测试结束之后只执行一次
2)说明
setUp:实现测试前的初始化工作
tearDown:实现测试结束后的清理工作
集合所有的测试用例并将测试结果独立地战士在测试架构中。
3)Unittest框架的四个概念
test fixtures:测试固件
test case:测试用例
test suit:测试套件
test runner:测试运行器
4)单元测试的两种加赠方法:
方法1:unittest.main() 方法加载单元测试的测试模块,执行顺序按照方法名的ascii码升序排序
方法2:将所有的test case 添加到Test Suite 集合中,然后一次性加载所有测试对象
3、代码举例
举例1:
#encoding=utf-8 import unittest # 被测试类 class myclass(object): @classmethod #可以不加,但是调用前需要实例化 def sum(self, a, b): return a + b #将两个传入参数进行相加操作 @classmethod #可以不加,但是调用前需要实例化 def sub(self, a, b): return a - b #将两个传入参数进行相减操作 class mytest(unittest.TestCase): @classmethod #必须加 def setUpClass(cls):#每个测试类的setup方法,只会执行一次 "初始化类固件,固件是准备的意思" print ( "----setUpClass") @classmethod #必须加 def tearDownClass(cls):#每个测试类的tearDown方法,只会执行一次 "重构类固件" print ( "----tearDownClass") # 初始化工作 def setUp(self):#每个测试方法均会执行一次 self.a = 3 self.b = 1 print ( "--setUp") # 退出清理工作 def tearDown(self):#每个测试方法均会执行一次 print ( "--tearDown") # 具体的测试用例,一定要以test开头 def testsum(self): #每个测试用例执行成功一次,打印一个 . # 断言两数之和的结果是否是4 self.assertEqual(myclass.sum(self.a, self.b), 4, ‘test sum fail‘) def testsub(self): # 断言两数之差的结果是否是2 self.assertEqual(myclass.sub(self.a, self.b), 2, ‘test sub fail‘) if __name__ == ‘__main__‘: unittest.main() # 启动单元测试
执行结果:
举例2:跳过指定的测试用例的三种方法
# coding=utf-8 import random import unittest import sys class TestSequenceFunctions(unittest.TestCase): a = 6 def setUp(self): self.seq = list(range(10)) @unittest.skip("skipping") # 无条件忽略该测试方法 def test_shuffle(self): random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, list(range(10))) self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) # 如果变量a > 5,则忽略该测试方法 @unittest.skipIf(a > 5, "condition is not satisfied!") def test_choice(self): element = random.choice(self.seq) self.assertTrue(element in self.seq) # 除非执行测试用例的平台是Linux平台,否则忽略该测试方法 win32是windows @unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux") #被忽略时打印 第二个参数 def test_sample(self): with self.assertRaises(ValueError): random.sample(self.seq, 20) for element in random.sample(self.seq, 5): self.assertTrue(element in self.seq) if __name__ == ‘__main__‘: # unittest.main() # 指定加载哪几个测试类,生成测试集合 suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions) suite = unittest.TestSuite(suite) unittest.TextTestRunner(verbosity = 2).run(suite)
结果:
D:学习自动化单元测试>py -3 e4_unittest_skip.py test_choice (__main__.TestSequenceFunctions) ... skipped ‘condition is not satisfied!‘ test_sample (__main__.TestSequenceFunctions) ... skipped ‘requires Linux‘ test_shuffle (__main__.TestSequenceFunctions) ... skipped ‘skipping‘ ---------------------------------------------------------------------- Ran 3 tests in 0.003s OK (skipped=3)
举例3:常用断言举例
#encoding=utf-8 import unittest import random # 被测试类 class MyClass(object): @classmethod def sum(self, a, b): return a + b @classmethod def div(self, a, b): return a / b @classmethod def retrun_None(self): return None # 单元测试类 class MyTest(unittest.TestCase): # assertEqual()方法实例 def test_assertEqual(self): # 断言两数之和的结果 # 一般不需要捕获异常,unittest会自动捕获异常 try: a, b = 1, 2 sum = 3 self.assertEqual(a + b, sum, ‘断言失败,%s + %s != %s‘ %(a, b, sum)) except AssertionError as e: print (e) # assertNotEqual()方法实例 def test_assertNotEqual(self): # 断言两数之差的结果 try: a, b = 5, 2 res = 1 self.assertNotEqual(a - b, res, ‘断言失败,%s - %s != %s‘ %(a, b, res)) except AssertionError as e: print (e) # assertTrue()方法实例 def test_assertTrue(self): # 断言表达式的为真 try: self.assertTrue(1 == 1, "表达式为假") except AssertionError as e: print (e) # assertFalse()方法实例 def test_assertFalse(self): # 断言表达式为假 try: self.assertFalse(3 == 2, "表达式为真") except AssertionError as e: print (e) # assertIs()方法实例 def test_assertIs(self): # 断言两变量类型属于同一对象 try: a = 12 b = a self.assertIs(a, b, "%s与%s不属于同一对象" %(a, b)) except AssertionError as e: print (e) # test_assertIsNot()方法实例 def test_assertIsNot(self): # 断言两变量类型不属于同一对象 try: a = 12 b = "test" self.assertIsNot(a, b, "%s与%s属于同一对象" %(a, b)) except AssertionError as e: print (e) # assertIsNone()方法实例 def test_assertIsNone(self): # 断言表达式结果为None try: result = MyClass.retrun_None() self.assertIsNone(result, "not is None") except AssertionError as e: print (e) # assertIsNotNone()方法实例 def test_assertIsNotNone(self): # 断言表达式结果不为None try: result = MyClass.sum(2, 5) self.assertIsNotNone(result, "is None") except AssertionError as e: print (e) # assertIn()方法实例 def test_assertIn(self): # 断言对象A是否包含在对象B中 try: strA = "this is a test" strB = "is" self.assertIn(strB, strA, "%s不包含在%s中" %(strB, strA)) except AssertionError as e: print (e) # assertNotIn()方法实例 def test_assertNotIn(self): # 断言对象A不包含在对象B中 try: strA = "this is a test" strB = "Selenium" self.assertNotIn(strB, strA, "%s包含在%s中" %(strB, strA)) except AssertionError as e: print (e) # assertIsInstance()方法实例 def test_assertIsInstance(self): # 测试对象A的类型是否值指定的类型 try: x = MyClass y = object self.assertIsInstance(x, y, "%s的类型不是%s" %(x, y)) except AssertionError as e: print (e) # assertNotIsInstance()方法实例 def test_assertNotIsInstance(self): # 测试对象A的类型不是指定的类型 try: a = 123 b = str self.assertNotIsInstance(a, b, "%s的类型是%s" %(a, b)) except AssertionError as e: print (e) # assertRaises()方法实例 def test_assertRaises(self): # 测试抛出的指定的异常类型 # assertRaises(exception) with self.assertRaises(TypeError) as cm: random.sample([1,2,3,4,5], "j") # 打印详细的异常信息 #print "===", cm.exception # assertRaises(exception, callable, *args, **kwds) try: self.assertRaises(ZeroDivisionError, MyClass.div, 3, 0) except ZeroDivisionError as e: print (e) # assertRaisesRegexp()方法实例 def test_assertRaisesRegexp(self): # 测试抛出的指定异常类型,并用正则表达式具体验证 # assertRaisesRegexp(exception, regexp) with self.assertRaisesRegex(ValueError, ‘literal‘) as ar: int("xyz") # 打印详细的异常信息 #print ar.exception # 打印正则表达式 #print "re:",ar.expected_regexp # assertRaisesRegexp(exception, regexp, callable, *args, **kwds) try: self.assertRaisesRegexp(ValueError, "invalid literal for.*XYZ‘$", int, ‘XYZ‘) except AssertionError as e: print (e) if __name__ == ‘__main__‘: # 执行单元测试 unittest.main()
举例4:生成图形化测试报告
导入文件htmlTestRunner.py ;放到python的安装目录下(D:Python37-32Libsite-packages)
运行对应的主方法:
import unittest import HTMLTestRunner if __name__ == ‘__main__‘ : # 加载当前目录下所有有效的测试模块(以test开头的文件),“.”表示当前目录 testSuite = unittest.TestLoader().discover(‘.‘) filename = "test.html" # 定义个报告存放路径,支持相对路径。 # 以二进制方式打开文件,准备写 fp = open(filename, ‘wb‘) # 使用HTMLTestRunner配置参数,输出报告路径、报告标题、描述,均可以配 runner = HTMLTestRunner.HTMLTestRunner(stream = fp, title = ‘Report_title‘, description = ‘Report_description‘) # 运行测试集合 runner.run(testSuite)
结果:
举例5:单元测试框架跑UI测试
#encoding=utf-8 import unittest from selenium import webdriver import time class GloryRoad(unittest.TestCase): def setUp(self): # 启动Chrome浏览器 # 驱动文件位置要改,本地自己的驱动 self.driver = webdriver.Chrome() def testSoGou(self): # 访问搜狗首页 self.driver.get("http://sogou.com") # 清空搜索输入框默认内容 self.driver.find_element_by_id("query").clear() # 在搜索输入框中输入“光荣之路自动化测试” self.driver.find_element_by_id("query").send_keys(u"WebDriver实战宝典") # 单击“搜索”按钮 self.driver.find_element_by_id("stb").click() # 等待3秒 time.sleep(3) assert u"吴晓华" in self.driver.page_source, u"页面中不存在要寻找的关键字!".encode("gbk") def testBing(self): # 访问bing首页 self.driver.get("http://cn.bing.com") # 清空搜索输入框默认内容 self.driver.find_element_by_id("sb_form_q").clear() # 在搜索输入框中输入“光荣之路自动化测试” self.driver.find_element_by_id("sb_form_q").send_keys(u"WebDriver实战宝典") # 单击“搜索”按钮 self.driver.find_element_by_id("sb_form_go").click() # 等待3秒 time.sleep(3) assert u"吴晓华" in self.driver.page_source, u"页面中不存在要寻找的关键字!".encode("gbk") def tearDown(self): # 退出浏览器 self.driver.quit() if __name__ == ‘__main__‘: unittest.main()
举例6:单元测试和ddt数据驱动结合
安装包:pip3 install ddt
代码:
import unittest import ddt @ddt.ddt class Praddt(unittest.TestCase): def setUp(self): print("my test start!") def tearDown(self): print("my test complete!") @ddt.data(["admin", "1qaz", "OK"], #一组数据,每一行都会触发运行 ["admin", "", "ERROR"], #另一组数据 ["1", "1qaz", "ERROR"], #另一组数据.. ["admin", "1234", "ERROR"], ["Admin", "1qaz", "ERROR"]) #实现了数据驱动,可以执行5次 @ddt.unpack def test_ddt(self, user, passwd, expect_value): print(user,passwd,expect_value) self.assertTrue(len(user)>0) if __name__ == ‘__main__‘: # 执行单元测试 unittest.main()
测试结果:
以上是关于单元测试框架unittest的主要内容,如果未能解决你的问题,请参考以下文章
基于appium实现的线性代码引用unittest单元测试框架