Unittest学习

优点

  • python内嵌的测试框架,无需安装即可使用
  • 执行多个case时,互不干扰,即使有一个case失败了,也不影响其余的case执行。

组成部分

  1. TestCase:测试用例类,编写的用例类需要继承该类。
  2. TestSuite:测试集,可以添加多个case,然后以添加的顺序执行用例。
  3. TestLoader:测试加载器,可以加载一类case,然后添加到TestSuite中。
  4. TextTestRunner:用例执行器,生成简单文本显示执行结果,一般以TestSuite为单位来执行用例。
  5. TestResult:测试结果。

实例:

1.

新建一个文件叫:case.py

import unittest

class study(unittest.TestCase):
    def setUp(self):
        print('测试开始前的准备函数')
    def test_01(self):
        print('测试用例01')
    def test_02(self):
        print('测试用例02')
    def tearDown(self):
        print('测试结束后的善后函数')

if __name__ == '__main__':
    unittest.main()

然后执行python case.py就可得到:

测试开始前的准备函数
测试用例01
测试结束后的善后函数
.测试开始前的准备函数
测试用例02
测试结束后的善后函数
.
----------------------------------------------------------------------
Ran 2 tests in 0.005s

OK

setUp()tearDown() 函数在每一个用例执行前都执行一遍。如果只需要在类层面执行一次这两种函数,可以使用 setUpClass()tearDownClass 函数,不过在使用时需要用@classmethod修饰。
例如:

import unittest

class study(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        print('测试开始前的准备函数,类层面')
    def test_01(self):
        print('测试用例01')
    def test_02(self):
        print(‘测试用例02')
    @classmethod
    def tearDownClass(self):
        print('测试结束后的善后函数,类层面')

if __name__ == '__main__':
    unittest.main()

执行结果:

测试开始前的准备函数,类层面
测试用例01
.测试用例02
.测试结束后的善后函数,类层面

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

2.

将刚才case.py中的两个测试用例添加到另一个文件的TestSuite中并执行:
case.py文件所在目录下新建一个文件run.py,内容为:

import unittest
from case import study
# 实例化
suite = unittest.TestSuite()
# 列表形式组合用例
case = [study('test_02'), study('test_01')]
suite.addTests(case)
# 实例化
runner = unittest.TextTestRunner()
runner.run(suite)

执行python run.py,结果为:

测试开始前的准备函数,类层面
测试用例02
.测试用例01
.测试结束后的善后函数,类层面

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

可以看到,用例的执行顺序也改变了。
suite添加用例还可以以下列方式进行:

suite.addTest(study('test_02'))
suite.addTest(study('test_01'))

不过这种方式比较繁琐。

3.

可以发现,上述的添加case的方法只适合与用例较少的情况,在用例非常多的情况下,为了方便添加,就需要使用TestLoader,即用例加载器。
接下来就对run.py进行改造:

import unittest
from case import study

suite = unittest.TestSuite()
loader = unittest.TestLoader().loadTestsFromTestCase(study)
suite.addTests(loader)
runner = unittest.TextTestRunner()
runner.run(suite)

执行结果:

测试开始前的准备函数,类层面
测试用例01
.测试用例02
.测试结束后的善后函数,类层面

----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

loader查找case的方式还有如下几种:

import case
loader = unittest.TestLoader().loadTestsFromModule(case)
# 感觉也是每次添加一个用例,不推荐
loader = unittest.TestLoader().loadTestsFromName('case.study.test_01')
# 如果有多个case文件,case, case1……,可以使用discover
loader = unittest.defaultTestLoader.discover(start_dir='path', pattern='case*.py')
# path即指这些case文件所在的绝对路径

4.

TextTestRunner在上面的例子中有所体现,基本上就是:

runner = unittest.TextTestRunner()
runner.run(suite)

这样的用法。

断言

测试用例执行需要用断言来判断是否成功
新建一个example01,内容:

import unittest

a, b = 1, 2
class study01(unittest.TestCase):
    def setUp(self):
        print('----start----')
    def test_01(self):
        self.assertEqual(a, b, 'a < b')
    def tearDown(self):
        print('-----end-----')

if __name__ == '__main__':
    unittest.main()

执行结果:

----start----
-----end-----
F
======================================================================
FAIL: test_01 (__main__.study01)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\weilong\Pworkspace\Test_study\Unitest_simple\example01.py", line 8, in test_01
    self.assertEqual(a, b, 'a < b')
AssertionError: 1 != 2 : a < b

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)

可以看到,如果断言失败,会显示预留的信息。
断言的类型:

assertEqual(a,b) a==b 值是否相等
aassertNotEqual(a,b) a!=b 值是否不相等
aasserIs(a,b) a is b 值是否相同
aassertIsNot(a,b) a is not b 值是否不同
assertIn(a,b) a in b a是否包含b
assertNotIn(a,b) a not in b a是否不包含b
ssertTrue(a) bool(a) is true 是否为真
assertFalse(a) bool(a)is false 是否为假
assertIsNone(a) a is None 是否为空
assertIsNotNone(a) a is None 是否不为空
assertIsInstance(a,b) Instance(a,b) a与b的数据类型一样
assertNotIsInstance(a) not Instance(a,b) a与b的数据类型不一样

跳过

有时候,因为环境或者需要等因素,一些用例需要进行跳过处理,这时候就需要用到@unittest.skip()来修饰用例。
改写example01:

import unittest

a, b = 1, 2
class study01(unittest.TestCase):
    def setUp(self):
        print('----start----')
    @unittest.skip('a != b')
    def test_01(self):
        self.assertEqual(a, b, 'a < b')
    def test_02(self):
        self.assertNotEqual(a, b, 'a = b')
    def tearDown(self):
        print('-----end-----')

if __name__ == '__main__':
    unittest.main()

执行结果:

s----start----
-----end-----
.
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK (skipped=1)

可以看懂跳过了一个测试用例。然后,skip()括号内的是reason,虽然执行结果没有显示,但其实是一个必要的参数,如果没填入会报错。
skip还有一种方式:

@unittest.skipIf(option, reason)

数据驱动

大量不同的数据进行相同的逻辑函数测试,可以用ddt模块,安装

pip install ddt

使用:

import unittest
from ddt import ddt, data

@ddt
class study02(unittest.TestCase):
    @data('a', 'b', 'c')
    # 即将a, b, c轮流与a比较,不相同的断言失败
    def test_01(self, text):
        self.assertEqual('a', text)
    
if __name__ == '__main__':
    unittest.main()

此外,还有以文件形式存储的数据驱动

import unittest
from ddt import ddt, file_data

@ddt
class study03(unittest.TestCase):
    @file_data('filepath')
    # **指字典形式。 *指列表形式
    def test_01(self, **text):
        print(text)
    
if __name__ == '__main__':
    unittest.main()

文件格式为jsonyaml
对于excelcsvtxt文件,需要先进行数据的读取。

unpack修饰会将列表数据拆分到参数中,不然多个参数时会将数据只传到第一个参数中。

测试报告

利用html-testRunner插件生成html测试报告,安装:

pip install html-testRunner

使用:

import unittest
from case import study
from HtmlTestRunner import HTMLTestRunner

suite = unittest.TestSuite()

loader = unittest.TestLoader().loadTestsFromTestCase(study)
suite.addTests(loader)
# 在该文件目录下创建report目录,将报告存入其中
runner = HTMLTestRunner(output='report')
runner.run(suite)

带中文的测试信息会产生乱码,所以要对该插件的result.py进行修改,
def generate_file(self, testRunner, report_name, report):方法下的with open(path_file, 'w') as report_file:改成with open(path_file, 'w',encoding='utf-8') as report_file:,这样就可以得到带中文的测试报告了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值