python_unittest框架

一、Unittest:

unittest是Python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架

二、Unittest核心工作原理:

unittest中最核心的四个概念是:test case, test suite, test runner, test fixture

1. TestCase

一个TestCase的实例,就是一个测试用例。
测试用例:一个完整的测试流程,包括测试前的准备工作(setUp)、测试过程的代码、善后工作(tearDown)
单元测试的本质也就在这里,一个测试用例,也就是一个完整的测试单元

2. TestSuit

一个功能的验证往往需要多个测试用例,把多个测试用例集合在一起执行,就产生的测试套件的概念TestSuite。
TestSuite用来组装单个测试用例。
通过addTest()加载TestCase到TestSuite中,从而返回一个TestSuite实例

3. TestRunner

测试执行。一般单元测试框架中都会提供丰富的执行策略和执行结果。
在unittest单元测试框架中,通过TextTestRunner类提供的run()方法来执行测试套件/测试用例。
TestRunner可以使用图形界面、文本界面,或返回一个特殊的值等方式,来表示测试结果

4. TestFixture

对一个测试用例环境的搭建和销毁,就是一个fixture,通过覆盖TestCase的setUp()和tearDown()方法来实现。
比如,可以在setUp()中通过建立数据库连接来初始化,在tearDown()中清除数据库产生的数据,关闭连接等

流程:

一个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执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件

三、Unittest实例:

先准备一些待测的方法:

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

简单实例:
接下来我们为这些方法写一个测试

import unittest 
from mathfunc import *


class TestMathFunc(unittest.TestCase):
    """Test mathfuc.py"""

    def test_add(self):
        """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(5, divide(6, 2))

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

在这里插入图片描述

从上面也可以看出,测试的执行跟方法的顺序没有关系,test_divide写在了第4个,但是却是第2个执行的。
每个测试方法均以 test开头,否则是不被unittest识别的

四:组织TestSuite:

上面的代码示例了如何编写一个简单的测试,但有两个问题,问题一:我们怎么控制用例执行的顺序呢?(这里的示例中的几个测试方法并没有一定关系,但之后你写的用例可能会有先后关系,需要先执行方法A,再执行方法B),我们就要用到TestSuite了。我们添加到TestSuite中的case是会按照添加的顺序执行的
问题二:是我们现在只有一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么进行组织,总不能一个个文件执行吧

上栗子:

在文件夹中,新建一个test_suite.py

import unittest
from UTest.test_mathfunc import *

if __name__ == '__main__':
    suite = unittest.TestSuite()

    tests = [TestMathFunc("test_add"),TestMathFunc("test_minus"),TestMathFunc("test_divide")]
    suite.addTests(tests)

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

测试结果:
在这里插入图片描述
能够看到一共运行了3个测试,失败了1个,并且给出了失败原因,5 != 3 也就是说我们的divide方法是有问题的

说明:
1、在第一行给出了每一个用例执行的结果的标识,成功是 .,失败是 F,出错是 E,跳过是 S。
2、在unittest.TestTestRunner()中加 verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果,即没有上面的结果中的第1行;如果设为 2,则输出详细的执行结果,如下:
在这里插入图片描述
可以看到,执行情况跟我们预料的一样:执行了三个case,并且顺序是按照我们添加进suite的顺序执行的。

上面用了TestSuite的 addTests() 方法,并直接传入了TestCase列表,我们还可以:

import unittest
from UTest.test_mathfunc import *
from UTest.mathfunc import *

if __name__ == '__main__':
    suite = unittest.TestSuite()

    # 添加多个Testcase至addTests
    # tests = [TestMathFunc("test_add"),TestMathFunc("test_minus"),TestMathFunc("test_divide")]
    # suite.addTests(tests)

    # 直接用addTest添加单个测试用力
    # suite.addTest(TestMathFunc('test_add'))

    # 用addTests + TestLoader
    # loadTestsFromName(),传入'模块名.TestCase名'
    #suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc'))
    # loadTestsFromNames(),类似,传入列表
    #suite.addTests(unittest.TestLoader().loadTestsFromNames(["test_mathfunc.TestMathfunc"]))
    # loadTestsFromTestCase()传入的是类
    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
    

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

将结果输出到文件中

用例组织好了,但结果只能输出到控制台,这样没有办法查看之前的执行记录,我们想将结果输出到文件
修改test_suite.py:

mport unittest
from UTest.test_mathfunc import *

if __name__ == '__main__':
    suite = unittest.TestSuite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

with open('UnittestTextReport.txt','a') as f:
    runner = unittest.TextTestRunner(f,verbosity=2)
    runner.run(suite)

执行此文件,可以看到,在同目录下生成了UnittestTextReport.txt,所有的执行报告均输出到了此文件中,这下我们便有了txt格式的测试报告了。

五:test fixture之setUp() tearDown()

如果我的测试需要在每次执行之前准备环境,或者在每次执行完之后需要进行一些清理怎么办?比如执行前需要连接数据库,执行完成之后需要还原数据、断开连接。总不能每个测试方法中都添加准备环境、清理环境的代码吧。
这就要涉及到我们之前说过的test fixture了,修改test_mathfunc.py:

mport unittest
from UTest.mathfunc import *


class TestMathFunc(unittest.TestCase):
    '''
    test_mathfunc.py
    '''

    def setUp(self):
        print("setUp")

    def tearDown(self):
        print("tearDown")

    def test_add(self):
        print("test_add")
        self.assertEqual(5,add(4,1))
        self.assertNotEqual(4,add(3,2))

    def test_minus(self):
        print("test_minus")
        self.assertEqual(6,minus(8,2))

    def test_multi(self):
        print("test_nulti")
        self.assertEqual(6,multi(3,2))
        self.assertEqual(5,multi(2.5,2))

    def test_divide(self):
        print("test_divide")
        self.assertEqual(2,divide(6,3))
        self.assertEqual(5,divide(6,2))



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

我们添加了 setUp() 和 tearDown() 两个方法(其实是重写了TestCase的这两个方法),这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,tearDown用来清理环境,已备之后的测试
测试结果:
在这里插入图片描述
可以看到setUp和tearDown在每次执行case前后都执行了一次
如果想要在所有case执行之前准备一次环境,并在所有case执行结束之后再清理环境,我们可以用 setUpClass() 与 tearDownClass():

class TestMathFunc(unittest.TestCase):
    '''
    test_mathfunc.py
    '''
    @classmethod
    def setUpClass(cls) -> None:
        print("setUpClass")

    @classmethod
    def tearDownClass(cls) -> None:
        print("tearDown")

测试结果:
在这里插入图片描述
可以看到setUpClass以及tearDownClass均只执行了一次
跳过某个Case:
如果我们临时想要跳过某个case不执行怎么办?unittest也提供了几种方法:

1、skip装饰器:
@unittest.skip("俺不想执行这个用例")
def test_divide(self):
    print("test_divide")
    self.assertEqual(2,divide(6,3))
    self.assertEqual(5,divide(6,2))

测试结果:
在这里插入图片描述
skip装饰器一共有三个 unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。

2、TestCase.skipTest()方法
def test_divide(self):
    self.skipTest("俺不想执行这个用例")
    print("test_divide")
    self.assertEqual(2,divide(6,3))
    self.assertEqual(5,divide(6,2))

测试结果:
在这里插入图片描述

总结:

1、unittest是Python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架
2、unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。
3、一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。
4、verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告
5、可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。
6、用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境
7、我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值