从 0 到 1 带你快速上手
Pytest 自动化测试框架

公开课 20:00 正式开始

讲师介绍

飞儿

  • 霍格沃兹测试开发学社讲师
  • 高级测试开发工程师
  • 《测试开发实战宝典》与《软件测试开发理论与项目实战教程》等书籍核心作者
  • 擅长业务测试、接口测试、自动化测试、测试工具开发
  • 曾为多家企业客户提供测试技术支持

大纲

  • 从零开始学习测试框架 Pytest 的用法
  • 学会测试用例的设计、编写与执行
  • 掌握 Pytest 的高阶用法:参数化,插件
  • 结合 Allure,输出图文并茂的测试报告
  • 手把手带你体验完整的 Python 自动化测试流程

成果展示

相关知识点

形式 章节
知识点 Pytest 命名规则
知识点 pycharm 配置与界面化运行
知识点 Pytest 测试用例结构
知识点 Pytest 测试用例断言
知识点 Pytest 测试框架结构
知识点 Pytest 运行用例
知识点 Pytest 测试用例调度与运行
知识点 Pytest 命令行常用参数
知识点 Pytest 参数化用例
知识点 Pytest 插件 【进阶】
知识点 Allure2 安装
知识点 Allure2 运行方式
知识点 Allure2 报告生成

实战思路

Pytest 环境准备

  • Python 安装配置:
    • 推荐 Python 版本:3.8 以上
    • 官方下载地址
    • 操作步骤:
      • 下载系统对应的安装程序。
      • 运行安装包。
      • 检查是否安装成功。
  • PyCharm 安装:
  • Pytest 安装:
    • pip install pytest
    • PyCharm 直接安装

被测对象介绍

  • 回合制游戏
    • 有两个英雄,分别是 EZ 和 Jinx。
    • 每个英雄都有血量属性和攻击力属性
      • EZ 初始值: 血量 1100; 攻击力 190
      • Jinx 初始值: 血量 1000; 攻击力 210
    • 战斗逻辑:
      • 战斗后血量 = 初始血量 - 对方攻击力
      • 一轮战斗后,对比双方战斗后血量,血量少的人输掉比赛
# src/fight_game.py

# 定义战斗函数
def fight(EZ_hp, EZ_power, Jinx_hp, Jinx_power):
    # 定义战斗结果
    fight_result = ""
    # 定义循环
    while True:
        # 定义最终血量的计算方式
        EZ_hp = EZ_hp - Jinx_power
        Jinx_hp = Jinx_hp - EZ_power

        # 打印两个英雄的最终血量的值
        print(f"EZ 剩余血量为:{EZ_hp}")
        print(f"Jinx 剩余血量为:{Jinx_hp}")

        # 判断输赢
        if EZ_hp > Jinx_hp:
            fight_result = "EZ 赢了"
        elif EZ_hp < Jinx_hp:
            fight_result = "Jinx 赢了"
        else:
            fight_result = "平局"
        # 当某一个英雄的血量小于或者等于 0 时跳出循环
        if EZ_hp <= 0 or Jinx_hp <= 0:
            # 跳出循环
            break
    # 返回战斗结果
    return fight_result

Pytest 编写规范

类型 规则
文件 test_开头 或者 _test 结尾
Test 开头
方法/函数 test_开头
注意:测试类中不可以添加__init__构造函数

Pytest 用例结构

  • 三部分构成:
    • 用例名称
    • 用例步骤
    • 用例断言
# tests/test_xxx.py

def test_XXX(self):
    # 测试步骤1
    # 测试步骤2
    # 断言  实际结果 对比 预期结果
    assert ActualResult == ExpectedResult

常用的断言方式

  • assert <bool expression>
# tests/test_assert.py

# assert xx :判断 xx 为真
def test_assert_true():
    a = 1
    assert a

# assert not xx :判断 xx 不为真
def test_assert_false():
    a = False
    assert not a

# assert a in b :判断 b 包含 a
def test_assert_in():
    a = "霍格沃兹测试开发学社"
    b = "霍格沃兹"
    assert b in a

# assert a == b :判断 a 等于 b
def test_assert_equal():
    a = "霍格沃兹测试开发学社"
    b = "霍格沃兹测试开发学社"
    assert a == b

# assert a != b :判断 a 不等于 b
def test_assert_unequal():
    a = "霍格沃兹测试开发学社"
    b = "霍格沃兹"
    assert a != b

针对回合制游戏完成自动化测试

创建 test_fight.py 文件。

# tests/test_fight.py

def test_fight_lose():
    # 定义英雄属性
    EZ_hp = 1100
    EZ_power = 190
    Jinx_hp = 1000
    Jinx_power = 210
    result = fight(EZ_hp, EZ_power, Jinx_hp, Jinx_power)
    # 打印战斗结果
    print(result)
    # 断言战斗结果
    assert result == "Jinx 赢了"

运行 Pytest 用例

  • PyCharm 直接执行
  • 命令行执行
    • 执行包下所有的用例:
      • pytest
    • 执行单独一个 pytest 模块:
      • pytest 文件名.py

框架结构

类型 规则
setup_module/teardown_module 全局模块级
setup_class/teardown_class 类级,只在类中前后运行一次
setup_function/teardown_function 函数级,在类外
setup_method/teardown_method 方法级,类中的每个方法执行前后
# tests/test_setup.py

def setup_module():
    print("模块级别的setup")

def teardown_module():
    print("模块级别的teardown")

def setup_function():
    print("函数级别 setup")

def teardown_function():
    print("函数级别 teardown")

def test_func1():
    print("测试 func1")

class TestDemo:
    def setup_class(self):
        print("类级别的setup")

    def teardown_class(self):
        print("类级别的teardown")

    def setup_method(self):
        print("方法级别的setup")

    def teardown_method(self):
        print("方法级别的teardown")

    def test_demo1(self):
        print("testdemo1")

    def test_demo2(self):
        print("testdemo2")

参数化实现 DDT

  • 通过参数的方式传递数据,从而实现数据和脚本分离。
  • 并且可以实现用例的重复生成与执行。
  • 装饰器:@pytest.mark.parametrize
@pytest.mark.parametrize(
  "param1, param2",
  [["p1_value","p2_value"], ["p1_value1","p2_value1"]]
)
def test_param(param1, param2):
    print(param1, param2)

Pytest 第三方插件 - pytest-ordering

  • 场景:
    • 对于集成测试,经常会有上下文依赖关系的测试用例。
    • 比如 10 个步骤,拆成 10 条 case,这时候能知道到底执行到哪步报错。
    • 用例默认执行顺序:自上而下执行
  • 解决:
    • 安装:
      • pip install pytest-ordering
    • 语法:
      • @pytest.mark.run(order=2)
# tests/test_order.py

import time
import pytest

value = 0


@pytest.mark.run(order=2)
def test_add2():
    print("I am 2")
    time.sleep(2)
    assert value == 10


@pytest.mark.run(order=1)
def test_add():
    global value
    value =10
    assert value == 10

Allure 报告

Allure 是一款灵活的测试报告工具,用 Java 语言开发。它可以生成详尽的测试报告,包括测试类别、步骤、日志、图片等,并生成高水准的统计报告。

Allure 还能轻松集成到 Jenkins 中,生成在线趋势汇总报告。随着软件测试领域的发展,对更清晰、更全面的测试报告需求不断增加,因此 Allure 也备受市场欢迎。

Allure 官网

Allure 安装

  1. 安装 Java,需要配置环境变量。
  2. 安装 Allure ,需要配置环境变量。
  3. 安装插件:
    • Python:pip install allure-pytest
  4. 环境验证:allure --version

测试报告生成的流程

  1. 运行测试用例,生成包含测试数据的“中间"测试结果。
  2. 通过命令解析中间结果,生成在线版本或静态资源报告。

生成报告

  • 使用 --alluredir 参数生成测试报告。
# 在测试执行期间收集结果
# —alluredir这个选项 用于指定存储测试结果的路径
pytest [测试用例/模块/包] --alluredir=./results --clean-alluredir

# 生成在线的测试报告
allure serve ./results

# 生成报告,指定输出路径,清理报告。
allure generate --clean results/html results -o results/html

案例

总结

  • Pytest 安装与配置
  • Pytest 编写规范
  • Pytest 用例结构
  • Pytest 用例编写
  • Pytest 用例执行
  • Pytest 框架结构应用
  • Pytest 参数化实现 DDT
  • Pytest 第三方插件
  • 生成 Allure 报告