一份经过时间检验的 Laravel PHPUnit 测试经验分享

简介: 一份经过时间检验的 Laravel PHPUnit 测试经验分享

介绍

作为开发者我们可能都有过这样的经历:

  • Laravel v7 都已经发布了,而自己维护的项目仍然是公司祖传的 v5.3,迟迟不敢升级。
  • 修复了一个注册功能的 bug,结果把登录功能搞崩了,直到用户反馈才知道。
  • 新增功能或者修改代码都束手束脚,生怕对项目造成破坏性影响。

而这些困境很大部分的原因在于项目缺少完善的测试,无法保障项目的健壮,接下来我们就来分享我司经过数年的实践,锤炼出来的一套成熟的测试工艺。

利用 Laravel 提供的测试工具

Laravel 对请求进行了封装,我们可以非常方便地在测试中发起各种请求,比如说测试用户列表。 下面是 Laravel 自带的示例代码

public function testBasicTest()
{
    $response = $this->get('/users');
    $response->assertStatus(200);
}

PHP

Copy

这里有几个问题:

  • 在运行测试前需要创建数据表。
  • 需要填充一些测试数据,否则测试空的用户列表没有太大意义。
  • 希望能验证请求返回的 response 数据是否符合预期。

下面我们就来一一解决以上问题。

Migrations

Laravel 提供了 migration 来创建和更改数据表结构,在测试启动前可以先运行 migrate 命令。随着时间的推移,表结构变化积累得越多,migration 耗时就会越长。

Migration 对数据库做增量修改的做法并没有给测试带来任何好处,相反,在运行测试之前如果能对数据库进行全量构造,性能会提高很多。所以我们创建了自动化工具,对于每次添加新的 migration,都会自动生成全量的表结构描述文件用于测试。

Seeding

有了上一步的 migration 生成的数据表,我们还需要往数据表中插入测试数据,Laravel 再次贴心的提供了 seeding 功能,但是 seed 文件是通过手写的数组来存放数据,比如像下面这个样子:

<?php
use Illuminate\Database\Seeder;
use DB;
class UsersTableSeeder extends Seeder
{
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'baijunyao',
        ]);
    }
}

PHP

Copy

我们的业务逻辑比较复杂,需要多套测试数据集,每套测试数据集中的数据又各有依赖,所以我们维护数套 YAML 格式存储的数据集,并实现了 YamlSeeder 来将 YAML 数据用于 seed 测试数据库。

users:
  - name: baijunyao

YAML

Copy

Assert Response

Laravel 提供了一系列的 assert 方法,但是一个一个的手动调用这些方法比较繁琐,手动硬编码 response 的数据就更加痛苦了。

public function testBasicTest()
{
    $response = $this->get('/users');
    $response->assertStatus(200);
    $response->assertJson([
        [
            'name' => 'baijunyao',
        ]
    ]);
}

PHP

Copy

我们的方案是开发了一套自动 snapshot 测试工具。我们的测试用例有两种模式运行测试:创建 snapshot 和执行测试。前者可以自动捕捉所有 API response 并以 JSON 格式存储,后者则会将该次测试输出和 snapshot 进行比较以做断言。以 JSON 格式存在的 snapshot 结果集随代码一同 commit 到代码仓库中,可以方便地追踪每次的代码修改对 response 造成的影响。

{
    "status_code": 200,
    "headers": {
        "cache-control": [
            "no-cache, private"
        ],
        "date": "Mon, 06-Jan-2020 00:00:00 GMT",
        "content-type": [
            "application\/json"
        ],
        "x-ratelimit-limit": [
            60
        ],
        "x-ratelimit-remaining": [
            59
        ],
        "set-cookie": [
            "foo=bar; expires=Mon, 06-Jan-2020 01:00:00 GMT; max-age=3600; path=\/; secure; httponly"
        ],
    },
    "content": [
        {
            "name": "baijunyao"
        }
    ]
}

JSON

Copy

这种比对整个 response 的方案中有一些细节需要注意,比如:

变量

有一些变量比如日期,可能造成每次的 response 都不一样,我们可以使用 Carbon 在测试模式中设置一个固定的当前日期。

Carbon::setTestNow(Carbon::create(2020, 1, 1, 0, 0, 0));

PHP

Copy

对于其他一些变量数据采用Mockery,无法 mock 的则忽略变量部分。

重置测试数据

因为新增数据的功能测试会真实的向数据库中插入一条数据,为了清理脏数据,Laravel 提供了 Illuminate\Foundation\Testing\RefreshDatabase trait,它使用的是数据库的事务,存在的问题是数据虽然重置了,但是并没有重置自增型的主键,会造成每次运行测试时 id 不确定的问题。我们的解决方案是通过 DB 监听执行的 SQL,然后通过 TRUNCATE 来清理被污染的数据。

app('db')->listen(function ($query) {
    // ...
});

PHP

Copy

数据库

Laravel 默认是使用 SQLite 作为数据库,我们使用的则是 MySQL,在每次启动测试前创建一个临时数据库,测试结束后销毁这个临时的数据库,借助于 Docker 我们可以最大程度的保障测试环境跟生产环境的一致性。

结语

编写测试代码是一个必要而且有价值的工作内容,它可以让我们有底气的进行功能开发,快速的进行迭代,希望我们的测试方案对您有所帮助,围绕着测试我们开发了一系列的扩展包来简化我们编写测试代码的工作,如果对我们的测试方案有兴趣,欢迎留言,我们会逐步进行更深入更详细的讲解并开源这些工具。

相关文章
|
数据可视化 C++ Python
案例实战 | Python 玩转 AB 测试中的分层抽样与假设检验!(附代码和数据集)(下)
在电商网站 AB 测试非常常见,是将统计学与程序代码结合的经典案例之一。尽管如此,里面还是有许多值得学习和注意的地方。 A/B 测试用于测试网页的修改效果(浏览量,注册率等),测试需进行一场实验,实验中控制组为网页旧版本,实验组为网页新版本,实验还需选出一个指标 来衡量每组用户的参与度,然后根据实验结果来判断哪个版本效果更好。 通过这些测试,我们可以观察什么样的改动能最大化指标,测试适用的改动类型十分广泛,上到增加元素的大改动,下到颜色小变动都可使用这些测试。
272 0
案例实战 | Python 玩转 AB 测试中的分层抽样与假设检验!(附代码和数据集)(下)
|
搜索推荐 Python
案例实战 | Python 玩转 AB 测试中的分层抽样与假设检验!(附代码和数据集)(上)
在电商网站 AB 测试非常常见,是将统计学与程序代码结合的经典案例之一。尽管如此,里面还是有许多值得学习和注意的地方。 A/B 测试用于测试网页的修改效果(浏览量,注册率等),测试需进行一场实验,实验中控制组为网页旧版本,实验组为网页新版本,实验还需选出一个指标 来衡量每组用户的参与度,然后根据实验结果来判断哪个版本效果更好。 通过这些测试,我们可以观察什么样的改动能最大化指标,测试适用的改动类型十分广泛,上到增加元素的大改动,下到颜色小变动都可使用这些测试。
242 0
案例实战 | Python 玩转 AB 测试中的分层抽样与假设检验!(附代码和数据集)(上)
电动车TIC(测试、检验和认证)
本文研究全球及中国市场电动车TIC(测试、检验和认证)现状及未来发展趋势,侧重分析全球及中国市场的主要企业,同时对比北美、欧洲、中国、日本、东南亚和印度等地区的现状及未来发展趋势
|
4天前
|
网络协议 安全 测试技术
性能工具之emqtt-bench BenchMark 测试示例
【4月更文挑战第19天】在前面两篇文章中介绍了emqtt-bench工具和MQTT的入门压测,本文示例 emqtt_bench 对 MQTT Broker 做 Beachmark 测试,让大家对 MQTT消息中间 BenchMark 测试有个整体了解,方便平常在压测工作查阅。
133 7
性能工具之emqtt-bench BenchMark 测试示例
|
4天前
|
测试技术 C语言
网站压力测试工具Siege图文详解
网站压力测试工具Siege图文详解
31 0
|
4天前
|
机器学习/深度学习 数据采集 人工智能
【专栏】AI在软件测试中的应用,如自动执行测试用例、识别缺陷和优化测试设计
【4月更文挑战第27天】本文探讨了AI在软件测试中的应用,如自动执行测试用例、识别缺陷和优化测试设计。AI辅助工具利用机器学习、自然语言处理和图像识别提高效率,但面临数据质量、模型解释性、维护更新及安全性挑战。未来,AI将更注重用户体验,提升透明度,并在保护隐私的同时,通过联邦学习等技术共享知识。AI在软件测试领域的前景广阔,但需解决现有挑战。
|
4天前
|
测试技术
如何管理测试用例?测试用例有什么管理工具?YesDev
该文档介绍了测试用例和测试用例库的管理。测试用例是描述软件测试方案的详细步骤,包括测试目标、环境、输入、步骤和预期结果。测试用例库用于组织和管理这些用例,强调简洁性、完整性和可维护性。管理者可以创建、删除、重命名用例库,搜索和管理用例,以及通过层级目录结构来组织用例。此外,还支持通过Excel导入和导出测试用例,以及使用脑图查看用例关系。后台管理允许配置全局别名,如用例状态、优先级和执行结果。
|
4天前
|
机器学习/深度学习 人工智能 运维
深入探索软件测试:策略、工具与未来趋势
【5月更文挑战第14天】在软件开发的生命周期中,测试环节扮演着至关重要的角色。它不仅保证产品能够达到预定的质量标准,还有助于提前发现并修复潜在的缺陷,从而减少维护成本和提高用户满意度。本文将深入探讨当前软件测试领域的最佳实践,包括测试策略的制定、工具的选择以及面对快速变化的技术环境如何保持测试活动的前瞻性和灵活性。通过分析自动化测试、性能测试和安全测试等关键领域,本文旨在为读者提供一个全面的软件测试指南,同时对未来的发展趋势进行预测。
|
4天前
|
SQL 测试技术 网络安全
Python之SQLMap:自动SQL注入和渗透测试工具示例详解
Python之SQLMap:自动SQL注入和渗透测试工具示例详解
28 0

热门文章

最新文章