软件测试 —— Python(七)之UnitTest框架与测试报告

其他Python知识参考:Python学习路线

目录

一、UnitTest介绍

1、框架

2、什么是UnitTest框架?

3、为什么使⽤UnitTest框架? 

4、UnitTest核⼼要素(unitest 的组成部分)

4.1、TestCase(最核⼼的模块)

4.2、TestSuite

4.3、TestRunner

4.4、TestLoader

4.5、Fixture 

二、TestCase(测试⽤例) 

1、步骤

2、代码

3、代码⽂件的命名不规范

4、代码运⾏没有结果 

5、没有找到⽤例

三、TestSuite 与 TestRunner 

1、步骤

2、示例

四、TestLoader (测试加载)

1、步骤

2、示例

五、Fixture(测试夹具)

1、方法级别(掌握)

2、类级别(掌握)

3、模块级别(了解)

4、示例

六、断言

1、assertEqual

2、assertIn

3、示例

七、参数化

1、安装插件

2、验证插件是否安装成功

3、参数化代码

4、跳过

八、测试报告

1、自带的测试报告

2、生成第三方的测试报告

3、总结


其他Python知识参考:Python学习路线

一、UnitTest介绍

1、框架

说明:

1. 框架英⽂单词framework

2. 为解决⼀类事情的功能集合

注意: 需要按照框架的规定(套路) 去书写代码

2、什么是UnitTest框架?

概念: UnitTest是Python⾃带的⼀个单元测试框架,⽤它来做单元测试

⾃带的框架(官⽅): 不需要单外安装, 只要安装了 Python, 就可以使⽤

        random, json, os, time

第三⽅框架: 想要使⽤ 需要先安装后使⽤

        (pytest) selenium , appium, requests 

单元测试框架: 主要⽤来做单元测试, ⼀般单元测试是开发做

对于测试来说, unittest 框架的作⽤是 ⾃动化脚本(⽤例代码) 执⾏框架(使⽤ unittest 框架来 管理、运⾏多个测试⽤例的) 

3、为什么使⽤UnitTest框架? 

1. 能够组织多个⽤例去执⾏

2. 提供丰富的断⾔⽅法(让程序代码代替⼈⼯⾃动的判断预期 结果和实际结果是否相符)

3. 能够⽣成测试报告

4、UnitTest核⼼要素(unitest 的组成部分)

4.1、TestCase(最核⼼的模块)

TestCase(测试⽤例), 注意这个测试⽤例是 unittest 框架的组成部分, 不是⼿⼯和⾃动化中我们所说的⽤例(Test Case)

主要作⽤: 每个 TestCase(测试⽤例) 都是⼀个代码⽂件, 在这个代码⽂件中, 来书写真正的⽤例代码

4.2、TestSuite

TestSuite(测试套件), ⽤来管理、组装(打包)多个 TestCase(测试⽤例) 的 

4.3、TestRunner

TestRunner(测试执⾏,测试运⾏), ⽤来执⾏TestSuite(测试套件)的 

4.4、TestLoader

TestLoader(测试加载), 功能是对 TestSuite(测试套件) 功能的补充, 管理、组装(打包)多个 TestCase(测试⽤例) 的 

4.5、Fixture 

Fixture(测试夹具), 书写在 TestCase(测试⽤例) 代码 中, 是⼀个代码结构, 可以在每个⽅法执⾏前后都会执⾏ 的内容

举例:

登录的测试⽤例, 每个⽤例中重复的代码就可以写在 Fixture 代码结构中, 只写⼀遍, 但每次⽤例⽅法的执⾏,都会执⾏ Fixture 中的代码

1. 打开浏览器

2. 输⼊⽹址

二、TestCase(测试⽤例) 

1. 是⼀个代码⽂件, 在代码⽂件中 来书写真正的⽤例代码

2. 代码⽂件的名字必须按照标识符的规则来书写(可以将代码的作⽤在⽂件的开头使⽤注释说明)

1、步骤

1. 导包 (unittest)

2. ⾃定义测试类

3. 在测试类中书写测试⽅法

4. 执⾏⽤例

2、代码

""" 
代码的⽬的: 学习 TestCase(测试⽤例)模块的书写⽅法 
"""
# 1, 导包 
import unittest
# 2, ⾃定义测试类, 需要继承 unittest 模块中的 TestCase 类即可 
class TestDemo(unittest.TestCase):
    # 3, 书写测试⽅法, 即 ⽤例代码. ⽬前没有真正的⽤ 例代码, 使⽤ print 代替
    # 书写要求, 测试⽅法 必须以 test_ 开头(本质是以 test 开头)
    def test_method1(self):
        print('测试⽅法 1')

    def test_method2(self):
        print('测试⽅法 2')

# 4, 执⾏⽤例(⽅法) 
# 4.1 将光标放在 类名的后边 运⾏, 会执⾏类中的所有的测试⽅法 
# 4.2 将光标放在 ⽅法名的后边 运⾏, 只执⾏当前的⽅法

3、代码⽂件的命名不规范

1. 代码⽂件的名字以数字开头

2. 代码⽂件名字中有空格

3. 代码⽂件名字有中⽂

4. 其他的特殊符号

 (数字, 字⺟, 下划线组成, 不能以数字开头)

4、代码运⾏没有结果 

右键运⾏没有 unittests for 的提示, 出现的问题解决⽅案:

⽅案1. 重新新建⼀个代码⽂件, 将写好的代码复制进去

⽅案2. 删除已有的运⾏⽅式

5、没有找到⽤例

测试⽅法中不是以 test_ 开头的, 或者单词写错了  

三、TestSuite 与 TestRunner 

TestSuite(测试套件): 管理 打包 组装 TestCase(测试⽤例) ⽂件的

TestRunner(测试执⾏): 执⾏ TestSuite(套件)

1、步骤

1. 导包(unittest)

2. 实例化(创建对象)套件对象

3. 使⽤套件对象添加⽤例⽅法

4. 实例化运⾏对象

5. 使⽤运⾏对象去执⾏套件对象

2、示例

TestSuite(测试套件): 是⽤来管理多个 TestCase(测试⽤ 例) 的, 先创建多个 TestCase(测试⽤例) ⽂件

方式一:

""" 
学习 TestSuite 和 TestRunner 的使⽤ 
"""

# 1. 导包(unittest) 
import unittest 
from testcase1 import TestDemo1 
from testcase2 import TestDemo2

# 2. 实例化(创建对象)套件对象, 
suite = unittest.TestSuite() 
# 3. 使⽤套件对象添加⽤例⽅法 
# ⽅式⼀, 套件对象.addTest(测试类名('⽅法名')) 
# 建议测试类名和⽅法名直接去复制,不要⼿写
suite.addTest(TestDemo1('test_method1')) 
suite.addTest(TestDemo1('test_method2')) 
suite.addTest(TestDemo2('test_method1')) 
suite.addTest(TestDemo2('test_method2'))

# 4. 实例化运⾏对象
runner = unittest.TextTestRunner()
# 5. 使⽤运⾏对象去执⾏套件对象 
# 运⾏对象.run(套件对象)
runner.run(suite)

方式二:

""" 
学习 TestSuite 和 TestRunner 的使⽤ 
""" 

# 1. 导包(unittest) 
import unittest
from testcase1 import TestDemo1 
from testcase2 import TestDemo2

# 2. 实例化(创建对象)套件对象,
suite = unittest.TestSuite()
# 3. 使⽤套件对象添加⽤例⽅法 
# ⽅式⼆ 将⼀个测试类中的所有⽅法进⾏添加 
# 套件对象.addTest(unittest.makeSuite(测试类名)) 
# 缺点: makeSuite() 不会提示
suite.addTest(unittest.makeSuite(TestDemo1)) suite.addTest(unittest.makeSuite(TestDemo2))

# 4. 实例化运⾏对象 
runner = unittest.TextTestRunner() 
# 5. 使⽤运⾏对象去执⾏套件对象 
# 运⾏对象.run(套件对象) 
runner.run(suite)

四、TestLoader (测试加载)

1、步骤

TestLoader (测试加载), 作用和 TestSuite 的作用是一样的, 对 TestSuite 功能的补充, 用来组装测试用例的

比如: 如果 TestCase 的代码文件有很多, (10 20, 30 ...)

- 使用步骤

1. 导包

2. 实例化测试加载对象并添加用例 ---> 得到的是 suite 对象

3. 实例化 运行对象

4. 运行对象执行套件对象 

2、示例

在一个项目中 TestCase(测试用例) 的代码,一般放在一个单独的目录 (case) 

"""
TestLoader 的使用
""" 
# 1, 导包 
import unittest

# 2, 实例化加载对象并添加用例 
# unittest.TestLoader().discover('用例所在的路径', '用例的代码文件名')
# 用例所在的路径,建议使用相对路径, 用例的代码文件名可以使用 *(任意多个任意字符) 通配符
# suite = unittest.TestLoader().discover('./case', 'test*.py')
# suite = unittest.TestLoader().discover('./case', '*test*.py')
# suite = unittest.TestLoader().discover('./case', '*test*')
suite = unittest.TestLoader().discover('./case', '*case1.py')


# 3, 实例化运行对象 
# runner = unittest.TextTestRunner() 
# # 4, 执行 # runner.run(suite)
# 可以将 3 4 步 变为一步 
unittest.TextTestRunner().run(suite)

五、Fixture(测试夹具)

Fixture(测试夹具) 是一种代码结构

在某些特定的情况下 会自动执行

1、方法级别(掌握)

每个测试方法(用例代码) 执行前后都会自动调用的结构

# 方法执行之前 
def setUp(self):
    # 每个测试方法执行之前都会执行 
    pass

# 方法执行之后 
def tearDown(self):
    # 每个测试方法执行之后都会执行 
    pass

2、类级别(掌握)

每个测试类中所有方法执行前后 都会自动调用的结构(在整个类中 执行之前执行之后个一次)

# 类级别的Fixture 方法, 是一个 类方法 
# 类中所有方法之前 
@classmethod def setUpClass(cls):
    pass

# 类中所有方法之后 
@classmethod def tearDownClass(cls):
    pass

3、模块级别(了解)

模块: 代码文件

每个代码文件执行前后执行的代码结构

# 模块级别的需要写在类的外边直接定义函数即可 
# 代码文件之前 
def setUpModule():
    pass

# 代码文件之后 
def tearDownModule():
    pass

注意方法级别和类级别的 前后的方法,不需要同时出现,根据用例代码的需要自行的选择使用 

4、示例

1. 打开浏览器(整个测试过程中就打开一次浏览器) 类级别

2. 输入网址(每个测试方法都需要一次) 方法级别

3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法

4. 关闭当前页面(每个测试方法都需要一次) 方法级别

2. 输入网址(每个测试方法都需要一次) 方法级别

3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法

4. 关闭当前页面(每个测试方法都需要一次) 方法级别

2. 输入网址(每个测试方法都需要一次) 方法级别

3. 输入用户名密码验证码点击登录(不同的测试数据) 测试方法

4. 关闭当前页面(每个测试方法都需要一次) 方法级别

5. 关闭浏览器(整个测试过程中就关闭一次浏览器) 类级别

import unittest

class TestLogin(unittest.TestCase):
    def setUp(self):
        """每个测试方法执行之前都会先调用的方法""" p
        rint('输入网址......')

    def tearDown(self): # -> None
        """每个测试方法执行之后都会调用的方法""" 
        print('关闭当前页面......')

    @classmethod 
    def setUpClass(cls): # -> None
        print('------1. 打开浏览器')

    @classmethod 
    def tearDownClass(cls): # -> None
        print('------5. 关闭浏览器')

    def test_1(self):
        print('输入正确用户名密码验证码,点击登录 1')

    def test_2(self):
            print('输入错误用户名密码验证码,点击登录 2')

六、断言

程序代替人工自动的判断预期结果实际结果是否相符.

断言的结果有两种:

        > True, 用例通过

        > False, 代码抛出异常, 用例不通过

在 unittest 中使用断言, 都需要通过 self.断言方法 来试验

1、assertEqual

self.assertEqual(预期结果, 实际结果)  # 判断预期结果和实际结果是否相等

1. 如果相等, 用例通过

2. 如果不相等,用例不通过, 抛出异常

2、assertIn

self.assertIn(预期结果, 实际结果)  # 判断预期结果是否包含在实际结果中

1. 包含 ,用例通过

2. 不包含, 用例不通过, 抛出异常

assertIn('admin', 'admin')  # 包含

assertIn('admin', 'adminnnnnnnn')  # 包含

assertIn('admin', 'aaaaaadmin')  # 包含

assertIn('admin', 'aaaaaadminnnnnnn')  # 包含

assertIn('admin', 'addddddmin')  # 不是包含

3、示例

import unittest
from tools import login

class TestLogin(unittest.TestCase):
    def test_username_password_ok(self):
        """正确的用户名和密码: admin, 123456, 登录成功""" 
        self.assertEqual('登录成功', login('admin', '123456'))

    def test_username_error(self):
        """错误的用户名: root, 123456, 登录失败""" 
        self.assertEqual('登录失败', login('root', '123456'))

    def test_password_error(self):
        """错误的密码: admin, 123123, 登录失败""" 
        self.assertEqual('登录失败', login('admin', '123123'))

    def test_username_password_error(self):
        """错误的用户名和错误的密码: aaa, 123123, 登录失败""" 
        # self.assertEqual('登录失败', login('aaa', '123123')) 
        self.assertIn('失败', login('aaa', '123123'))

七、参数化

参数化,在测试方法中, 使用 变量 来代替具体的测试数据, 然后使用传参的方法将测试数据传递给方法的变量

好处: 相似的代码不需要多次书写.

工作中场景:

1. 测试数据一般放在 json 文件中

2. 使用代码读取 json 文件,提取我们想要的数据 ---> [(), ()] or [[], []]

1、安装插件

unittest 框架本身是不支持 参数化, 想要使用参数化,需要安装插件来完成

- 联网安装(在 cmd 窗口安装 或者 )

        pip install parameterized

-----pip 是 Python 中包(插件) 的管理工具, 使用这个工具下载安装插件

2、验证插件是否安装成功

1. pip list  # 查看到 parameterized

2. 新建一个 python 代码文件, 导包验证 from pa... import pa...

3、参数化代码

1. 导包 unittest / parameterized

2. 定义测试类

3. 书写测试方法(用到的测试数据使用变量代替)

4. 组织测试数据并传参

 

 json数据:

[
  {

    "desc": "正确的用户名和密码", 
    "username": "admin", 
    "password": "123456", 
    "expect": "登录成功" 
  }, 
  { 
    "desc": "错误的的用户名", 
    "username": "root", 
    "password": "123456", 
    "expect": "登录失败" 
  }, 
  { 
    "desc": "错误的的密码", 
    "username": "admin", 
    "password": "123123", 
    "expect": "登录失败" 
  }
]
# 1. 导包 unittest/ pa 
import json
import unittest 
from parameterized import parameterized 
from tools import login

# 组织测试数据 [(), (), ()] or [[], [], []] 
def build_data():
    with open('data.json', encoding='utf-8') as f: 
        result = json.load(f) # [{}, {}, {}] 
        data = [] 
        for i in result: # i {}
            data.append((i.get('username'),i.get('password'),i.get('expect')))

    return data

# 2. 定义测试类 
class TestLogin(unittest.TestCase):
    # 3. 书写测试方法(用到的测试数据使用变量代替) 
    @parameterized.expand(build_data()) 
    def test_login(self, username, password, expect):
        self.assertEqual(expect, login(username, password))
# 4. 组织测试数据并传参(装饰器 @)

4、跳过

对于一些未完成的或者不满足测试条件测试函数和测试类, 不想执行,可以使用跳过

使用方法, 装饰器完成

代码书写在 TestCase 文件 

# 直接将测试函数标记成跳过

@unittest.skip('跳过额原因')

# 根据条件判断测试函数是否跳过 , 判断条件成立, 跳过

@unittest.skipIf(判断条件, '跳过原因')

import unittest

# version = 30 
version = 29

class TestDemo(unittest.TestCase):
    @unittest.skip('没有什么原因,就是不想执行') 
    def test_1(self):
        print('测试方法 1')

    @unittest.skipIf(version >= 30, '版本大于等于 30, 不用测试')
    def test_2(self):
        print('测试方法 2')
    
    def test_3(self):
        print('测试方法 3')

八、测试报告

1、自带的测试报告

只有单独运行 TestCase 的代码,才会生成测试报告 

2、生成第三方的测试报告

1. 获取第三方的 测试运行类模块, 将其放在代码的目录中

2. 导包 unittest

3. 使用套件对象, 加载对象 去添加用例方法

4. 实例化第三方的运行对象, 并运行 套件对象

# 1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中 
# 2. 导包 unittest 
import unittest f
rom HTMLTestRunner import HTMLTestRunner

# 3. 使用 套件对象, 加载对象 去添加用例方法 
suite = unittest.defaultTestLoader.discover('.', 'pa1.py') 
# 4. 实例化 第三方的运行对象 并运行 套件对象 
# HTMLTestRunner() 
# stream=sys.stdout, 必填,测试报告的文件对象(open ), 注意点,要使用 wb 打开 
# verbosity=1, 可选, 报告的详细程度,默认 1 简略, 2 详细 
# title=None, 可选, 测试报告的标题 
# description=None 可选, 描述信息, Python 的版本, pycharm 版本

# file = 'report.html' # 报告的后缀是.html 
file = 'report1.html' # 报告的后缀是.html 
with open(file, 'wb') as f:
    # runner = HTMLTestRunner(f) # 运行对象 
    runner = HTMLTestRunner(f, 2, '测试报告', 'python 3.6.8 ') # 运行对象 
    # 运行对象执行套件, 要写在 with 的缩进中 
    runner.run(suite)

3、总结

1. 组织用例文件(TestCase 里边), 书写参数化, 书写断言, 书写 Fixture, 书写 跳过, 如果单个测试测试文 件, 直接运行, 得到测试报告, 如果有多个测试文件, 需要组装运行生成测试报告

2. 使用 套件对象组装, 或者使用 加载对象组装

3. 运行对象 运行

3.1 运行对象 = 第三方的运行类(文件对象(打开文件需要使用 wb 方式))

3.2 运行对象.run(套件对象)

import unittest 
from HTMLTestRunnerCN import HTMLTestReportCN

# 组装用例方法 
suite = unittest.defaultTestLoader.discover('.', '*pa1.py')

# 实例化运行对象 
with open('report_cn.html', 'wb') as f:
    runner = HTMLTestReportCN(f)
    runner.run(suite)

其他Python知识参考:Python学习路线 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心上学事上练

感谢您的支持,让我们一起成长

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值