java的单元测试框架Junit和TestNG,python里面也有单元测试框架-unittest,相当于是一个python版的junit。python里面的单元测试框架除了unittest,还有一个pytest框架,但是用的比较少
unittest注意点:
导入unittest模块
类名的第一个字母大写;
类要继承unittest.TestCase;
测试函数前必须加test,否则不会被当作测试用例来执行;
setUp()和tearDown()方法每个测试用例都会执行;
代码示例1:简单用法
#encoding=utf-8 import unittest import random class TestSequenceFunctions(unittest.TestCase): def setUp(self): # 初始化一个递增序列 self.seq = range(10) print ("setup completed!") def test_run(self): # 从序列seq中随机选取一个元素 element = random.choice(self.seq) # 验证随机元素确实属于列表中 self.assertTrue(element in self.seq) def test_sth(self): assert 1==1 def tearDown(self): print ("tearDown completed") class TestDictValueFormatFunctions(unittest.TestCase): def setUp(self): self.seq = list(range(10)) def test_shuffle(self): # 随机打乱原seq的顺序 random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, list(range(10))) # 验证执行函数时抛出了TypeError异常 self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) if __name__ == '__main__': unittest.main()
说明:
setUp:做初始化的工作,不是必须有这个函数
tearDown:清理的工作,不是必须有这个函数
unittest.main():将所有继承自unittest.TestCase的子类中的方法都执行
assertRaises();第一个参数表示抛出的异常类型,第二个参数是要执行的函数,第三个参数是函数传入的参数
代码示例2:初始化只执行一次的方法
#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): "初始化类固件" print ("----setUpClass") @classmethod def tearDownClass(cls): "重构类固件" print ("----tearDownClass") # 初始化工作 def setUp(self): self.a = 3 self.b = 1 print ("--setUp") # 具体的测试用例,一定要以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() # 启动单元测试
说明:setUpClass()和tearDownClass()在每个类中只执行一次
代码示例3:按数字或字母顺序执行测试case
#encoding=utf-8 import unittest from Calc import Calc class MyTest(unittest.TestCase): @classmethod def setUpClass(self): print ("单元测试前,创建Calc类的实例") self.c = Calc() # 具体的测试用例,一定要以test开头,执行顺序按照字母顺序开头 def test_0add(self): print ("run add()") self.assertEqual(self.c.add(1, 2, 12), 15, 'test add fail') def test_1sub(self): print ("run sub()") self.assertEqual(self.c.sub(2, 1, 3), -2, 'test sub fail') def test_2mul(self): print ("run mul()") self.assertEqual(Calc.mul(2, 3, 5), 30, 'test mul fail') def test_3div(self): print ("run div()") self.assertEqual(Calc.div(8, 2, 4), 1, 'test div fail') def test4(self): print('not start with test') if __name__ == '__main__': unittest.main()# 启动单元测试
说明:
测试用例(test_*)的执行顺序是根据1-2-3执行的,也就是说根据用例名称来顺序执行的,如果是字母开头的话同理
test4这个方法没有执行,说明测试用例只能以test开头
代码示例4:根据实际需要有跳过某些测试case
#encoding=utf-8 import random,sys,unittest class TestSeqFunctions(unittest.TestCase): a = 1 def setUp(self): self.seq = list(range(20)) @unittest.skip("skipping")#无条件忽略此测试方法 def test_shuffle(self): random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq,list(range(20))) self.assertRaises(TypeError,random.shuffle,(1,2,3)) @unittest.skipIf(a>5,"condition is not satisfied!")#如果a>5忽略此测试方法 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(TestSeqFunctions) suite = unittest.TestSuite(suite) unittest.TextTestRunner(verbosity = 2).run(suite)
说明:
@unittest.skip("skipping")#无条件忽略此测试方法
@unittest.skipIf(a > 5, "condition is not satisfied!"):满足第1个参数指定的条件,则忽略该测试方法
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux"):除非是第1个参数指定的条件,否则忽略此方法
没有使用unittest.main()是因为此种方式会将所有的测试类都执行,用unittest.TestLoader().loadTestsFromTestCase(TestSeqFunctions)指定执行的测试类
代码示例5:测试集组合
TestCalc.py:
#encoding=utf-8 import unittest import random from Calc import Calc class TestCalcFunctions(unittest.TestCase): def setUp(self): self.c=Calc() print ("setup completed!") def test_sum(self): self.assertTrue(self.c.add(1,2,3,4)==10) def test_sub(self): self.assertTrue(self.c.sub(100,20,30,40)==10) def test_mul(self): self.assertTrue(self.c.mul(1,2,3,40)==240) def test_div(self): self.assertTrue(self.c.div(100,10,2)==5) def tearDown(self): print ("test completed!") def tearDown(self): print ("tearDown completed") if __name__ == '__main__': unittest.main()
unittest_suite.py
#encoding=utf-8 import random import unittest from TestCalc import TestCalcFunctions class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.seq = list(range(10)) def tearDown(self): pass def test_choice(self): # 从序列seq中随机选取一个元素 element = random.choice(self.seq) # 验证随机元素确实属于列表中 self.assertTrue(element in self.seq) 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) class TestDictValueFormatFunctions(unittest.TestCase): def setUp(self): self.seq = list(range(10)) def tearDown(self): pass def test_shuffle(self): # 随机打乱原seq的顺序 random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, list(range(10))) # 验证执行函数时抛出了TypeError异常 self.assertRaises(TypeError, random.shuffle, (1, 2, 3)) if __name__ == '__main__': # 根据给定的测试类,获取其中所有以“test”开头的测试方法,并返回一个测试套件 suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions) suite2 = unittest.TestLoader().loadTestsFromTestCase(TestDictValueFormatFunctions) suite3 = unittest.TestLoader().loadTestsFromTestCase(TestCalcFunctions)
# 将多个测试类加载到测试套件中
#通过调整suit2和suite1的顺序,可以设定执行顺序
suite = unittest.TestSuite([suite2, suite1,suite3])
# 设置verbosity = 2,可以打印出更详细的执行信息
unittest.TextTestRunner(verbosity = 2).run(suite)
代码示例6:unittest中的断言方法
#encoding=utf-8 import unittest,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): # 断言两数之和的结果 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(ValueError) as cm: random.sample([1,2,3,4,5], 6) # 打印详细的异常信息 #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.assertRaisesRegexp(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()
说明:
assertEqual(first, second, msg=None):如果两个对象不相等,返回False,第三个参数个msg是遇到异常后自定义输出信息
常用方法:
assertEqual(first, second, msg=None):判断两个对象相等,first == second
assertNotEqual(first, second, msg=None):判断两个对象不相等,first != second
assertIn(member, container, msg=None):判断字符串是否包含,member in container
assertNotIn(member, container, msg=None):判断字符串不包含,member not in container
assertTrue(expr, msg=None):判断是否为真,expr is True
assertFalse(expr, msg=None):判断是否为假,expr is False
assertIsNone(self, obj, msg=None):判断是否为None, obj is None
assertIsNotNone(self, obj, msg=None):判断不为None, obj is not None
代码示例7:生成HTMLTestRunner测试报告
HTMLTestRunner用来生成HTML测试报告,是对python标准库unittest的一个扩展,使用前需要下载HTMLTestRunner.py文件,下载成功后放到…pythonLib目录下:
python2下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html
python3下载地址:http://pan.baidu.com/s/1dEZQ0pz
代码:
# coding=utf-8 import unittest import HTMLTestRunner import math class Calc(object): def add(self, x, y, *d): # 加法计算 result = x + y for i in d: result += i return result def sub(self, x, y, *d): # 减法计算 result = x - y for i in d: result -= i return result class SuiteTestCalc(unittest.TestCase): def setUp(self): self.c = Calc() @unittest.skip("skipping") def test_Sub(self): print ("sub") self.assertEqual(self.c.sub(100, 34, 6), 61, u'求差结果错误!') def testAdd(self): print ("add") self.assertEqual(self.c.add(1, 32, 56), 89, u'求和结果错误!') class SuiteTestPow(unittest.TestCase): def setUp(self): self.seq = range(10) # @unittest.skipIf() def test_Pow(self): print ("Pow") self.assertEqual(pow(6, 3), 2161, u'求幂结果错误!') def test_hasattr(self): print ("hasattr") # 检测math模块是否存在pow属性 self.assertTrue(hasattr(math, 'pow1'), u"检测的属性不存在!") if __name__ == "__main__": suite1 = unittest.TestLoader().loadTestsFromTestCase(SuiteTestCalc) suite2 = unittest.TestLoader().loadTestsFromTestCase(SuiteTestPow) suite = unittest.TestSuite([suite1, suite2]) #unittest.TextTestRunner(verbosity=2).run(suite) filename = "test.html" # 定义个报告存放路径,支持相对路径。 # 以二进制方式打开文件,准备写 fp = open(filename, 'wb') # 使用HTMLTestRunner配置参数,输出报告路径、报告标题、描述,均可以配 runner = HTMLTestRunner.HTMLTestRunner(stream = fp, title = u'测试报告', description = u'测试报告内容') # 运行测试集合 runner.run(suite)
说明:
import HTMLTestRunner:将模块导入
HTMLTestRunner.HTMLTestRunner(stream = fp,title = u'测试报告', description = u'测试报告内容'):使用HTMLTestRunner配置参数,输出报告路径、报告标题、描述
runner.run(suite):运行测试集合
代码示例8:运行当前目录下所有的测试模块
以文本方式运行:
以文本方式运行:
#encoding=utf-8 import unittest if __name__ == '__main__' : # 加载当前目录下所有有效的测试模块(以test开头的文件),“.”表示当前目录 testSuite = unittest.TestLoader().discover('.') unittest.TextTestRunner(verbosity = 2).run(testSuite)
生成html报告:
#encoding=utf-8 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)
————————————————
原文链接:https://blog.csdn.net/kongsuhongbaby/article/details/84111435