unitTest单元测试框架

一、单元测试的定义:
1:什么是单元测试?
  还记不记得我们软件测试学习的时候,按照定义:单元测试就是对单个模块或者是单个类或者单个函数进行测试,一般是开发做的,按照阶段来分,一般就是单元测试、集成测试(接口测试)、系统测试(系统之间的联调测试)、验收测试
2:为什么要做单元测试?
  1)单元测试之后,才是集成测试,单个单个的功能模块测试通过之后,才能把单个功能模块集成起来做集成测试,为了从底层发现bug,减少合成后出现的问题。
  2)越早发现bug越好,这样可以早点发现问题,不然问题累计到后面,如果做错了就要推倒重来-对于时间和经费来说,是非常浪费的!
  3)对于我们测试来说:我们就单元测试是为了执行测试用例!校验程序代码之间的运行逻辑

说白了也就是一句话:单元测试是测代码,相当于白盒测试,检查代码的逻辑以及功能有没有出问题!!!

比如:看接下来的一个例子,测某一个账号密码登录的功能,检查代码有没有问题

def login_check(username=None, password=None):
    """
    登录校验的函数
    :param username: 账号
    :param password:  密码
    :return: dict type
    """
    if username != None and password != None:
        if username == 'python31' and password == 'lemonban':
            return {"code": 0, "msg": "登录成功"}
        else:
            return {"code": 1, "msg": "账号或密码不正确"}
    else:
        return {"code": 1, "msg": "所有的参数不能为空"}

这段代码是开发人员写的,我们作为测试人员仅仅是去测这些代码有没有问题,怎么去测呢?需要我们自己亲自手写代码

像这个简单的登录案例,一般有这几种情况:

1,账号密码均正确
2,账号正确,密码错误
3,账号错误,密码正确
4,账号为空
5,密码为空

if __name__ == '__main__':
    # ------------------测试函数正常登录-----------------------------------
    
    # 第一步:准备用例数据
    expected = {"code": 0, "msg": "登录成功"}
    data = ("python31", "lemonban")
    # 第二步:传入参数,获取实际结果
    res = login_check(*data)
    # 第三步:判断用例是否通过(比对预期结果和实际结果)
    if res == expected:
        print("用例执行通过!")
    else:
        print("用例执行不通过!!!")
           
    # ---------------------------测试函数传入错误密码的情况--------------------------------------------
    
    # 第一步:准备用例数据
    expected = {"code": 0, "msg": "登录成功"}
    data = ("python31", "lemonban123")
    # 第二步:传入参数,获取实际结果
    res = login_check(*data)
    # 第三步:判断用例是否通过(比对预期结果和实际结果)
    if res == expected:
        print("用例执行通过!")
    else:
        print("用例执行不通过!!!")

# 这些代码是散的,一般不会这样去写,所以我们后面会有更完整的模块代码

 

unittest四大核心概念:

1,TestCase:测试用例
测试用例类:测试用例以类的形式去定义,并且一定要继承unittest中的unittest.TestCase
测试用例方法:用例类里面的每一个以test开头的方法,就是一条测试用例

2,TestSuite:测试套件 (用来存放测试用例的,相当于一个用例的集合)

3,TestRunner:测试运行程序

4,fixture:测试夹具(测试的前置后置条件处理)

一、TestCase:测试用例

 请看下面一段代码:

import unittest
from day_13.login import login_check


class TestLogin(unittest.TestCase):
    """登录的测试用例类"""

    def test_login_pass(self):
        """登录成功的用例"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "python31", "password": "lemonban"}
        # 1.2预期结果
        expected = {"code": 0, "msg": "登录成功"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)  # 比较第一个参数和第二个参数


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

 

 上面这段代码运行截图:

 因为,我只写了一个测试用例的函数,所以只有1条执行用例显示出来了结果,接下来,我来补充后面几个用例,看看运行跑一下会有什么样的结果:

注意:如果你的代码报错,无法导入unittest,unittest那里标记红色波浪线,那就说明你一开始没有导入,现在教你一个快速安装的方法:看下面的截图:

 好的,继续,接下来,我来补充后面几个用例,看看运行跑一下会有什么样的结果:

class TestLogin(unittest.TestCase):
    """登录的测试用例类"""

    def test_login_pass(self):
        """账号密码均正确,登录成功"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "python31", "password": "lemonban"}
        # 1.2预期结果
        expected = {"code": 0, "msg": "登录成功"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)

    def test_login_pwd_error(self):
        """密码错误"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "python31", "password": "lemonban123"}
        # 1.2预期结果
        expected = {"code": 1, "msg": "账号或密码不正确"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)

    def test_login_user_error(self):
        """账号错误"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "python999", "password": "lemonban"}
        # 1.2预期结果
        expected = {"code": 1, "msg": "账号或密码不正确"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)

    def test_login_user_is_none(self):
        """账号为空"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "", "password": "lemonban"}
        # 1.2预期结果
        expected = {"code": 1, "msg": "所有的参数不能为空"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)

    def test_login_pwd_is_none(self):
        """密码为空"""

        # 第一步:准备用例数据
        # 1.1用例输入的数据
        data = {"username": "python31", "password": ""}
        # 1.2预期结果
        expected = {"code": 1, "msg": "所有的参数不能为空"}

        # 第二步:调入被测的功能函数(请求接口),传入参数
        res = login_check(**data)

        # 第三步:比对预期结果和实际结果(断言)
        self.assertEqual(expected, res)


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

我一共写了5条用例,在上面的代码中,那看看运行结果截图:

 那具体怎么看没通过的用例?点击即可

 说明开发人员写的这段代码是有问题的,可有的人会问,是哪段代码有问题,我怎么看不出,这个不必深究,反正咱们测试人员已经测出bug了,代码的逻辑问题,需开发人员自己去修改,

附上那段有问题的代码,也就是最前面的那段:

 二、TestSuite:测试套件

TestSuite:测试套件 (用来存放测试用例的,相当于一个用例的集合)

如果用例一旦数量较多,比如20个,30个,那还会像上面这样一个一个去写吗?不会,此时,我们可以用到Testsuite这个测试套件,具体的步骤接下来看我慢慢讲解:

首先我们需要在项目中建一个文件夹File-->dirctory,命名为testcase,然后在这个专门存放测试用例的文件夹下,把用例按照模块去写进去,比如,我们要测试登录这个功能模块,那我们命名为test_login

如果要测试注册功能,就命名为test_register,如果要测试退出功能,就命名为test_exit,这里的每一个命名都必须以test开头,然后,比如在测试登录模块中,我们写了5个用例,当然,在实际的项目中,可以根据不同的需求

来在每一个你要测试的模块中写多个用例,我们这里是相当于把功能先分开,再在每个功能里写多个用例,如果需要执行用例,后面可以直接调用来跑程序看结果

当然,我们也得单独在项目中新建一个run.py文件,这个是专门用来运行程序的

 再来看看run.py文件中的代码:

import unittest
from unittestreport import TestRunner
# 第一步:创建一个测试套件
suite = unittest.TestSuite()

# 第二步:将测试用例添加到套件中
# 2.1 创建加载器:
loader = unittest.TestLoader()
# 2.2加载用例到套件中
# 第一种:通过测试用例类去加载
from day_13.testcase.test_login import TestLogin
suite.addTest(loader.loadTestsFromTestCase(TestLogin))

# 第三步:执行测试用例类
runner = TestRunner(suite)
runner.run()

 其中第二步:将测试用例加载到套件中,一共有三种方式,这里我先讲第一种,但是第一种用的不多,待会我3种都会讲,其中第三种用的是最多的,工作种也常用的。

那么运行一下,看看截图效果:

 再点击.report.html,运行看测试报告:

 

 因为这份测试报告,有点长,不方便一次截图成功,所以我就截图3次,展示出来,这样看起来,是不是感觉高大上的样子,没错,这就是用unittest这个测试框架的好处,很秀很秀!!!

 这仅仅是其中一种风格,还有另外一种风格,

 看看另外一种的风格:

 

 

 所以,我们在run.py文件中,可以自由设置这些生成报告的参数。

 继续,上面只讲了一种方式,另外两种方式去加载用例,先上代码,再看截图解析:

"""
用例加载的过程:
1、先找指定路径中test开头的python文件
2、再找Test开头文件中继承unittest.TestCase的用例类
3、再去找用例类中以test开头的方法

测试用例执行的顺序
1、模块按照ASCII码排序
2、类名按照ASCII码排序
3、方法名按照ASCII码排序
"""

import unittest
# 第一步:创建一个测试套件
suite = unittest.TestSuite()

# 第二步:将测试用例添加到套件中
# 2.1 创建加载器:
loader = unittest.TestLoader()

# 2.2加载用例到套件中
# 第一种:通过测试用例类去加载
# from day_13.testcase.test_login import TestLogin
# suite.addTest(loader.loadTestsFromTestCase(TestLogin))

# 第二种:通过测试用例模块去加载
# from day_13.testcase import test_login
# suite.addTest(loader.loadTestsFromModule(test_login))

# 第三种:指定用例所在文件路径去加载(工作中常用!!!)
suite.addTest(loader.discover(r"C:\Users\Administrator\PycharmProjects\example\day_13\testcase"))

# 第三步:执行测试用例
runner = unittest.TextTestRunner()
runner.run(suite)

 

 三、TestRunner: 测试运行程序

 这部分的内容,主要是用来执行测试用例和生成测试报告的,先看代码,再看截图:

import unittest
from unittestreport import TestRunner
# 第一步:创建一个测试套件
suite = unittest.TestSuite()
# 第二步:将测试用例添加到套件中
# 2.1 创建加载器:
loader = unittest.TestLoader()
# 2.2加载用例到套件中
# 第一种:通过测试用例类去加载
from day_13.testcase.test_login import TestLogin
suite.addTest(loader.loadTestsFromTestCase(TestLogin))
# 第三步:执行测试用例类
runner = TestRunner(suite,
                    filename="report.html",
                    report_dir=".",
                    title='测试报告',
                    tester='excellent',
                    desc="excellent执行测试生成的报告",
                    templates=1   # 这里可以生成两个风格不同的报告,待会给大家看一下
                    )
runner.run()

 这个run.py主要是和测试套件suite一起用,用来运行程序,

四、fixture测试夹具

fixture:测试用例环境的搭建与销毁,测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)

setUpClass(只执行一次)
setUp
tearDown
tearDownClass(只执行一次)

import unittest


class TestRegister(unittest.TestCase):

    def test_01(self):
        """比对1和100"""
        print("-----------执行test_01------------")
        self.assertEqual(100, 100)

    def test_02(self):
        """比对1000和1000"""
        print("-----------执行test_02------------")
        self.assertEqual(1000, 1000)

    def setUp(self):
        # 每条测试用例执行之前都会调用该方法(有多少用例执行多少次)
        print("-------------setup----------")

    def tearDown(self):
        # 每条测试用例执行之后都会调用该方法(有多少用例执行多少次)
        print("-------------tearDown----------")

    @classmethod
    def setUpClass(cls):
        # 测试类里面的用例执行之前会调用该方法(只会执行一次)
        print("-------------setUpClass----------")

    @classmethod
    def tearDownClass(cls):
        # 测试类里面的用例执行之后会调用该方法(只会执行一次)
        print("-------------tearDownClass----------")

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

 

 

未完待续。。。。。。。。。。。。。。。。。。。。。。。

 

 
posted @ 2020-08-06 18:41  excellent_1  阅读(337)  评论(0编辑  收藏  举报