Python + UnitTest 软件测试流程总结

以测试用户登录流程为例:

TestCase:

TestCase 主要用来编写测试用例,这里结合 **断言(assertEqual 和 assertIn)**进行判断,避免了手动书写判断。

python 复制代码
# tools.py
# 登录验证方法
def login(username, password):
    if username == 'admin' and password == '123456':
        return '登录成功'
    else:
        return '登录失败'
python 复制代码
# TestCase.py
# 导入 unittest
import unittest
from tools import login


class TestLogin(unittest.TestCase):
    def test_username_password_ok(self):
        self.assertEqual('登录成功', login('admin', '123456'))

    def test_username_error(self):
        self.assertEqual('登录失败', login('root', '123456'))

    def test_password_error(self):
        self.assertEqual('登录失败', login('admin', '123123'))

    def test_username_password_error(self):
        # self.assertEqual('登录失败', login('root', '123123'))
        self.assertIn('失败', login('aaa', '123123')) # 结果中包含"失败"即可

TestSuite:

TestSuite 用来管理多个 TestCase 文件,使用 unittest.TestSuite() 实例化套件对象,再使用套件对象添加用例方法。

假如创建多个 TestCase 文件:

python 复制代码
# testCase1.py
# 导包
import unittest

# 自定义测试类,继承 unittest 类中 testCase 类
class testDemo1(unittest.TestCase):
    # 测试方法(用例代码)
    def method1(self):
        print('测试方法1-1')

    def method2(self):
        print('测试方法1-2')
python 复制代码
# testCase2.py
# 导包
import unittest

# 自定义测试类,继承 unittest 类中 testCase 类
class testDemo2(unittest.TestCase):
    # 测试方法(用例代码)
    def method1(self):
        print('测试方法2-1')

    def method2(self):
        print('测试方法2-2')

TestRunner:

用来执行对象。

python 复制代码
# TestSuite_Runner.py
# TestSuite用来管理多个TestCase文件
# 1.导包
import unittest
# 2.实例化(创建对象)套件对象
from testCase1 import testDemo1
from testCase2 import testDemo2
from TestCase import TestLogin

suite = unittest.TestSuite()
# 3.使用套件对象添加用例方法
# 方法一:套件对象.addTest(测试类名('方法名'))
suite.addTest(testDemo1('method1'))
suite.addTest(testDemo1('method2'))
suite.addTest(testDemo2('method1'))
suite.addTest(testDemo2('method2'))

# 方法二:将一个测试类中的所有方法进行添加
# 套件对象.addTest(unittest.makeSuite(测试类名))
suite.addTest(unittest.makeSuite(testDemo1))
suite.addTest(unittest.makeSuite(testDemo2))
suite.addTest(unittest.makeSuite(TestLogin))

# 4.实例化运行对象
runner = unittest.TextTestRunner()

# 5.使用运行对象去执行套件对象
# 运行对象.run(套件对象)
runner.run(suite)

TestLoader:

用于多个 TestCase 中有多个 Method 时,写法较简便

python 复制代码
# TestLoader.py
# 1.导包
import unittest

# 2.实例化加载对象并添加用例
# unittest.TestLoader().discover('用例所在的路径', '用例的代码文件名')
suite = unittest.TestLoader().discover('./case', '*.py')
# suite = unittest.defaultTestLoader().discover('./case', '*.py') 两种写法

# 将3.4.合并
unittest.TextTestRunner().run(suite)

TestFixture:

在执行每个测试方法的前后会出现一些重复操作,可以使用 TestFixture 进行书写。

python 复制代码
# TestFixture.py
import unittest

class TestLogin(unittest.TestCase):
    # 1.打开浏览器(整个测试过程中就打开一次浏览器) 类级别
    @classmethod
    def setUpClass(cls) -> None:
        print('打开浏览器')

    # 2.输入网址(每个测试方法都需要一次) 方法级别
    def setUp(self):
        # 每个测试方法执行之前都会调用的方法
        print('输入网址')

    # 3.输入用户名密码验证码点击登录(不同的测试数据) 测试方法
    def test_1(self):
        print('输入正确信息,点击登录1')

    def test_2(self):
        print('输入错误信息,点击登录2')

    # 4.关闭当前页面(每个测试方法都需要一次) 方法级别
    def tearDown(self):
        # 每个测试方法执行之后都会调用的方法
        print('关闭当前页面')

    # 5.关闭浏览器(整个测试过程中就关闭一次浏览器) 类级别
    @classmethod
    def tearDownClass(cls) -> None:
        print('关闭浏览器')

Skip:

不想执行某个测试用例时,可以进行直接跳过(skip)或者条件触发(skipIf)跳过。

python 复制代码
# skip.py
# 导包
import unittest

version = 30

# 自定义测试类
class testDemo(unittest.TestCase):
    # 测试方法
    @unittest.skip('直接跳过')
    def test_method1(self):
        print('测试方法111')

    @unittest.skipIf(version >= 30, '版本高跳过测试')
    def test_method2(self):
        print('测试方法222')

    def test_method3(self):
        print('测试方法333')
# 执行用例(方法)

Parameterized:

在实际开发中,测试用例的数据不能写死,这时用到json文件的读取,之后利用 parameterized 对读取函数进行调用。

首先执行 pip install parameterized 下载;

之后在模块中导入 from parameterized import parameterized

python 复制代码
# 导入unittest/parameterized
import json
import unittest
from parameterized import parameterized
from tools import login


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

# 定义测试类
class TestLogin(unittest.TestCase):
    # 书写测试方法(用到的测试数据使用变量代替)
    @parameterized.expand(build_data())
    def test_login(self, username, password, expect):
        self.assertEqual(expect, login(username, password))

这里的 data.json:

python 复制代码
[
  {
    "desc": "正确用户名密码",
    "username": "admin",
    "password": "123456",
    "expect":"登录成功"
  },
  {
    "desc": "错误用户名",
    "username": "root",
    "password": "123456",
    "expect":"登录失败"
  },
  {
    "desc": "错误密码",
    "username": "admin",
    "password": "123123",
    "expect":"登录失败"
  }
]

在此过程中会生成测试报告,在终端中执行代码后,按照以下步骤可以进行查看:

运行html文件即可,效果如图:

这样生成的测试报告相对简陋,可以使用第三方库生成,在当前目录中放入顶部的两个文件。

接下来书写以下代码:

python 复制代码
# 利用第三方生成测试报告
# 中文版
# 1.获取第三方的 测试运行类模块,将其放在代码的目录中
# 2.导包 unittest
import unittest
from HTMLTestRunnerCN import HTMLTestReportCN

# 3.使用 套件对象,加载对象 去添加用例方法
suite = unittest.defaultTestLoader.discover('.', 'pa*login.py')
# 4.实例化 第三方的运行对象
file = 'report_cn.html'
with open(file, 'wb') as f:
    # 运行对象(第二个参数是:是否详细 1/2,第三个参数是报告标题,第三个参数是python/pycharm版本)
    runner = HTMLTestReportCN(f, 2, '测试报告中文版', 'python 3.6.7')
    # 5.运行 套件对象
    runner.run(suite)

# --------------------上下两端代码不要一起执行------------------------

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

# 3.使用 套件对象,加载对象 去添加用例方法
suite = unittest.defaultTestLoader.discover('.', 'pa*login.py')
# 4.实例化 第三方的运行对象
file = 'report.html'
with open(file, 'wb') as f:
    # 运行对象
    runner = HTMLTestRunner(f, 1, '测试报告', 'python 3.6.8')
    # 5.运行 套件对象
    runner.run(suite)

效果如下:

相关推荐
wjs20241 分钟前
jEasyUI 树形网格动态加载详解
开发语言
用户8356290780514 分钟前
Python 操作 Word 文档节与页面设置
后端·python
西西弗Sisyphus7 分钟前
Python 闭包的经典坑
python·闭包
西西弗Sisyphus11 分钟前
Python 在dataclasses 里,field() 能给可变、不可变数据分别设置安全的默认值
python·field·dataclasses
xlq2232222 分钟前
41.线程封装与互斥
linux·开发语言
西西弗Sisyphus29 分钟前
Python @dataclass 有 `__post_init__` 和 无 `__post_init__` 的对比
python·dataclass·__post_init__
独隅29 分钟前
PyCharm 开启硬换行的方法
ide·python·pycharm
不爱吃炸鸡柳32 分钟前
算法复杂度从入门到精通:时间与空间复杂度全解析
开发语言·c++·算法
游乐码41 分钟前
c#lambad表达式
开发语言·c#
weixin_408099671 小时前
python请求文字识别ocr api
开发语言·人工智能·后端·python·ocr·api·ocr文字识别