unittest框架最核心的四个概念:

一、unittest中测试用例的编写规范

在测试类当中,以test_开头,定义测试函数
每一个test_开头的函数,就是一个测试用例

用例编写步骤:
1 导入unittest模块,被测文件或者其中的类
2 创建一个测试类,并继承unittest模块中的TestCase类
3 定义测试函数,函数名以test_开头(一个test开头的方法就是一条测试用例

4 将测试用例执行的代码逻辑写到对应的测试方法中:
第一步:准备用例数据
第二步: 调用被测的功能函数(发送请求调用接口),获取实际结果
第三步: 断言,预期结果与实际结果的对比

下面编写测试登陆功能的测试用例:

登录的功能逻辑定义在login模块里

import unittest  # 引入 unittest
from python01.python02.login import login_check  # 导入login模块的登录函数


class TestLogin(unittest.TestCase):  # 定义测试类,继承unittest.TestCase
    def test_login_ok(self):  # 用例1
        # 第一步:准备用例数据
        params = { 'username': "cyy", "password": 123456}
        expected = { "code":0,"msg":"登录成功"}
        # 第二步:调用被测的功能函数(发送请求调用接口),获取实际结果
        result = login_check(**params)
        # 第三步:断言
        self.assertEqual(result, expected)

上述只是执行了一条用例,下面再看下五条用例的:

用例1 账号密码正确
入参:账号cyy,密码:123456
预期结果:{“code”:0,“msg”:“登录成功”}
实际结果:

用例2 账号正确,密码错误
入参:账号cyy,密码:fdgg
预期结果:{“code”:1,“msg”:“账号或密码不正确”}
实际结果:

用例3 账号错误,密码正确
入参:账号cyy1,密码:123456
预期结果:{“code”:1,“msg”:“账号或密码不正确”}
实际结果:

用例4 账号为空
入参:账号,密码:123456
预期结果:{“code”:1,“msg”:“所有的参数不能为空”}
实际结果:

用例5 密码为空
入参:账号cyy,密码:
预期结果:{“code”:1,“msg”:“所有的参数不能为空”}
实际结果:

import unittest  # 引入 unittest
from python01.python02.login import login_check  # 导入login模块的登录函数


class TestLogin(unittest.TestCase):  # 定义测试类,继承unittest.TestCase
    def test_login_ok(self):  # 用例1
        # 第一步:准备用例数据
        params = { 'username': "cyy", "password": 123456}
        expected = { "code":0,"msg":"登录成功"}
        # 第二步:调用被测的功能函数(发送请求调用接口),获取实际结果
        result = login_check(**params)
        # 第三步:断言
        self.assertEqual(result, expected)

    def test_login_password_wrong(self):  # 用例2
        params = { 'username': "cyy", "password": "fdgg"}
        expected = { "code": 1, "msg": "账号或密码不正确"}
        result = login_check(**params)
        self.assertEqual(result, expected)

    def test_login_user_wrong(self):  # 用例3
        params = { 'username': "cyy1", "password": 123456}
        expected = { "code": 1, "msg": "账号或密码不正确"}
        result = login_check(**params)
        self.assertEqual(result, expected)

    def test_login_no_user(self):  # 用例4
        params = { 'username': None, "password": 123456}
        expected = { "code": 1, "msg": "所有的参数不能为空"}
        result = login_check(**params)
        self.assertEqual(result, expected)

    def test_login_no_password(self):  # 用例5
        params = { 'username': "cyy", "password": None}
        expected = { "code": 1, "msg": "所有的参数不能为空"}
        result = login_check(**params)
        self.assertEqual(result, expected)

# 以上代码存于 test_case_01.py模块 

执行结果:

这里要注意,每个用例之间都是互相独立,如果其中一个用例报错了,不会影响其他用例的执行。

其中,我们断言用到的是assertEqual(a,b),作用是判断a和b是否相等,如果不相等则断言失败,报错AssertionError,而AssertionError是unittest框架识别用例失败的标识之一
另外unittest还有很多常用的断言方法如下:

二、收集用例TestSuite(测试套件),TestLoader加载用例

import unittest
# 1、创建套件
s = unittest.TestSuite()
# 2、创建一个用例加载器,并加载测试用例到套件(一般用TestLoader加载用例(收集用例))
s = unittest.TestLoader().discover("D:\pythoncharm01\python01")
print(type(s))# 打印出是一个TestSuite类(把发现的测试用例丢到TestSuite类里面)

# 以上代码存于 run.py模块,与test_case_01.py模块同级目录
   
 unittest.TestLoader().discover(搜索目录),搜索用例的方式:discover
 从start_directory这个目录下开始,搜索所有的测试用例,并加载到测试套件中。遵循以下原则:
 1、指定搜索目录
 2、文件过滤规则:以文件名匹配(test*.py),以test开头,.py结尾
 3、在文件当中过滤用例:继承了unittest.TestCase类的测试类,类当中以test_开头的测试函数。
这种方式方便以后的更改,因为是从目录中获取的


还有其他的用例收集方法,例如:
 实例化测试套件TestSuite
 s = unittest.TestSuite()
 1 添加一个用例 addTest(类名(”用例名“))
 s.addTest()
 2 添加多个用例 addTest(类名(”用例名1),类名(”用例名2),类名(”用例名3))
 s.addTests()
 3 TestLoader还可以通过类名、模块名,方式去收集用例
 
 这些收集用例方法比较费劲一般不用,了解即可。

三、执行用例+测试报告

为了验证第二点收集用例功能,同级目下再创建一个测试用例模块(定义了两条用例,一条是错的),看执行用例时是否会和test_case_01.py模块的用例一起加载出来

接下来我们要运行测试用例,并生成结果

这里我们用一个今年7月份发布的一个资源包unittestreport,关于它的详细介绍可以到PYPI了解
安装:pip install unittestreport

import unittest
# 1、创建套件
s = unittest.TestSuite()
# 2、创建一个用例加载器,并加载测试用例到套件(一般用TestLoader加载用例(收集用例))
s = unittest.TestLoader().discover("D:\pythoncharm01\python01")

##########################################################################

from unittestreport import TestRunner #从unittestreport中导入TestRunner类
#先实例化TestRunner,
runner = TestRunner(s,filename = "python01.html",tester='小菜',desc="小菜项目测试报告")
# 再执行用例,生成报告
runner.run()

#以上代码存于 run.py模块

关于括号里面填写的参数意思,可以进入源码进行查看:

执行后,生成如下测试报告:

一共7条用例,其中5条是test_case_01.py模块的,还有两条是test_case_02.py模块的

再介绍一个方法,这种方式生成的报告也还不错
#安装:pip install BeautifulReport
from BeautifulReport import BeautifulReport

br = BeautifulReport(s)
br.report("12月1号测试报告","python02.html")

## 都是一样的套路:先实例化,再运行用例,生成html报告

再扩展个可以减少代码的写法

四、前置后置条件fixture

有时候会遇到一些特殊情况,如果要在用例执行前做一些环境的准备工作,在用例执行后做一些清理工作该怎么办?
这就涉及到我们编写用例用到的前置后置(fixture),就是平常我们功能用例编写用到的前置/后置条件(可有可无)
1 setUp(前置条件),tearDown(后置条件) -类下面的每一个用例在执行之前,会执行setUp, 在每一个用例执行之后,会执行teardown。

import unittest
from python01.python02.login import login_check


class TestLogin(unittest.TestCase):
    def setUp(self) -> None:
        print('前置条件')

    def tearDown(self) -> None:
        print("后置条件")

    def test_login_ok(self):  # 用例1
        res = login_check("cyy", 123456)
        self.assertEqual(res, { "code": 0, "msg": "登录成功"})

    def test_login_password_wrong(self):  # 用例2
        res = login_check("cyy", 789465)
        self.assertEqual(res, { "code": 1, "msg": "账号或密码不正确"})
执行如下:
Ran 2 tests in 0.002s
OK
前置条件
后置条件
前置条件
后置条件

2 setUpClass,tearDownClass,类里面的第一个用例执行之前会执行setUpClass,类里面的最后一个用例执行之后才执行tearDownClass

import unittest
from python01.python02.login import login_check


class TestLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        print("前置条件")

    @classmethod
    def tearDownClass(cls) -> None:
        print("后置条件")

    def test_login_ok(self):  # 用例1
        res = login_check("cyy", 123456)
        self.assertEqual(res, { "code": 0, "msg": "登录成功"})

    def test_login_password_wrong(self):  # 用例2
        res = login_check("cyy", 789465)
        self.assertEqual(res, { "code": 1, "msg": "账号或密码不正确"})

执行结果如下:

Ran 2 tests in 0.001s
OK
前置条件
后置条件

以上unittest框架四大核心概念介绍完毕,接下来,再介绍点其他知识

五、用例执行顺序:ASCII码

ASCII吗的大小规则:0-9<A-Z<a-z

例如文件名,test_c.py和test_a.py,就会先执行test_a.py模块
然后进入到文件内部,测试用例执行的顺序也是识别每个函数名,从函数名不同的地方开始识别
若想自己指定顺序,在文件名或者用例名称上做改动

六、ddt数据驱动测试 data driven test

假如有一个测试流程是不变的,针对这个流程设计了几十条测试用例(流程不变,变的是测试数据),就可以用ddt数据驱动模块。数据驱动思想。

注意:由于现在好多人理解的数据驱动思想不一致,所以我们不能说特别掌握,只能说这个场景可以用数据驱动思想去实现。

首先要安装 pip install ddt
1、引入ddt——-import ddt
2、在测试类名的上面,用@ddt.ddt,
3、在测试函数上面,用@ddt.data(*列表)
4、在测试函数的参数中,定义一个参数用来接收每一组测试数据

import unittest  # 引入 unittest
from python01.python02.login import login_check  # 导入login模块的登录函数

datas = [{ "username": "cyy", "password": 123456, "check": { "code": 0, "msg": "登录成功"}},
         { "username": "cyy", "password": 12345, "check": { "code": 1, "msg": "账号或密码不正确"}},
         { "username": "cy", "password": 123456, "check": { "code": 1, "msg": "账号或密码不正确"}},
         { "username": None, "password": 123456, "check": { "code": 1, "msg": "所有的参数不能为空"}},
         { "username": "cyy", "password": None, "check": { "code": 1, "msg": "所有的参数不能为空"}},

         ]
import ddt  #导入ddt


@ddt.ddt  # 在测试类名的上面,用@ddt.ddt
class TestLogin(unittest.TestCase):
    @ddt.data(*datas)  #在测试函数上面,用@ddt.data(*列表) #拆包后将多组测试数据依次传递给一个测试流程
    def test_login_ok(self, case):  #在测试函数的参数中,定义一个case参数用来接收每一组测试数据
        result = login_check(case["username"], case["password"])

        self.assertEqual(result, case["check"])

这就是数据驱动测试,就可不用每条数据写一条用例了

本文地址:https://blog.csdn.net/cai217/article/details/110356685