作为开发者我们可能都有过这样的经历:
而这些困境很大部分的原因在于项目缺少完善的测试,无法保障项目的健壮,接下来我们就来分享我司经过数年的实践,锤炼出来的一套成熟的测试工艺。
Laravel 对请求进行了封装,我们可以非常方便地在测试中发起各种请求,比如说测试用户列表。 下面是 Laravel 自带的示例代码:
public function testBasicTest()
{
$response = $this->get('/users');
$response->assertStatus(200);
}
这里有几个问题:
下面我们就来一一解决以上问题。
Laravel 提供了 migration 来创建和更改数据表结构,在测试启动前可以先运行 migrate
命令。随着时间的推移,表结构变化积累得越多,migration 耗时就会越长。
Migration 对数据库做增量修改的做法并没有给测试带来任何好处,相反,在运行测试之前如果能对数据库进行全量构造,性能会提高很多。所以我们创建了自动化工具,对于每次添加新的 migration,都会自动生成全量的表结构描述文件用于测试。
有了上一步的 migration 生成的数据表,我们还需要往数据表中插入测试数据,Laravel 再次贴心的提供了 seeding 功能,但是 seed 文件是通过手写的数组来存放数据,比如像下面这个样子:
<?php
use Illuminate\Database\Seeder;
use DB;
class UsersTableSeeder extends Seeder
{
public function run()
{
DB::table('users')->insert([
'name' => 'baijunyao',
]);
}
}
我们的业务逻辑比较复杂,需要多套测试数据集,每套测试数据集中的数据又各有依赖,所以我们维护数套 YAML 格式存储的数据集,并实现了 YamlSeeder
来将 YAML 数据用于 seed 测试数据库。
users:
- name: baijunyao
Laravel 提供了一系列的 assert
方法,但是一个一个的手动调用这些方法比较繁琐,手动硬编码 response 的数据就更加痛苦了。
public function testBasicTest()
{
$response = $this->get('/users');
$response->assertStatus(200);
$response->assertJson([
[
'name' => 'baijunyao',
]
]);
}
我们的方案是开发了一套自动 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"
}
]
}
这种比对整个 response 的方案中有一些细节需要注意,比如:
有一些变量比如日期,可能造成每次的 response 都不一样,我们可以使用 Carbon 在测试模式中设置一个固定的当前日期。
Carbon::setTestNow(Carbon::create(2020, 1, 1, 0, 0, 0));
对于其他一些变量数据采用Mockery,无法 mock 的则忽略变量部分。
因为新增数据的功能测试会真实的向数据库中插入一条数据,为了清理脏数据,Laravel 提供了 Illuminate\Foundation\Testing\RefreshDatabase
trait,它使用的是数据库的事务,存在的问题是数据虽然重置了,但是并没有重置自增型的主键,会造成每次运行测试时 id
不确定的问题。我们的解决方案是通过 DB
监听执行的 SQL,然后通过 TRUNCATE
来清理被污染的数据。
app('db')->listen(function ($query) {
// ...
});
Laravel 默认是使用 SQLite 作为数据库,我们使用的则是 MySQL,在每次启动测试前创建一个临时数据库,测试结束后销毁这个临时的数据库,借助于 Docker 我们可以最大程度的保障测试环境跟生产环境的一致性。
编写测试代码是一个必要而且有价值的工作内容,它可以让我们有底气的进行功能开发,快速的进行迭代,希望我们的测试方案对您有所帮助,围绕着测试我们开发了一系列的扩展包来简化我们编写测试代码的工作,如果对我们的测试方案有兴趣,欢迎留言,我们会逐步进行更深入更详细的讲解并开源这些工具。
请关注我们的微信公众号「RightCapital」
本文为白俊遥原创文章,转载无需和我联系,但请注明来自白俊遥博客https://baijunyao.com 欢迎捐赠赞赏加入组织创建QQ群及捐赠渠道
自由自在 :加油
2022-06-01 09:56:02 回复
Stephen :1
2021-12-10 17:08:45 回复
-就不再错过 :嘎嘎嘎
2021-08-19 07:12:18 回复
无痕202121221 :2
2021-07-14 02:05:08 回复
flNikolai :nice
2021-04-30 01:06:44 回复
Slave code :老哥,laravel-bjyblog博客问题 1、文章富文本编辑器加上一个上传附件的功能就好了2、文章详情富文本演示样式和用户端显示样式差距有点大尤其是文本换行,在用户端扎堆了
2021-03-09 00:13:36 回复
云淡风晴 :可以在 https://github.com/baijunyao/laravel-bjyblog/issues 创建 issue 来描述需求;我抽空实现;
2021-03-10 06:05:00 回复
flNikolai :请先登录后回复评论
2021-04-29 07:35:51 回复
悟空 :您好,我是晨阳博客站长。麻烦把我的名字改为初晨博客,把链接改为:https://www.i54.top,主要这个域名已备案,用着方便,最后一次了,麻烦您了
2021-02-27 00:08:14 回复
云淡风晴 :已修改;
2021-02-27 19:09:50 回复
悟空 :您好,我是Black博客站长,我对com域名心动,域名已更换,烦劳更新信息,链接为cle4.com,名称为晨阳博客
2021-02-23 21:21:57 回复
麦志健 :很久没跟新了你 https://www.maizhijian.com/ 欢迎申请友链
2021-01-21 23:28:28 回复
kehanzhong :
2020-12-07 19:47:29 回复
张先生 :可以,bug搞定了,www.fenglicnc.com谢谢
2020-11-17 19:38:52 回复
张小宇 :插个眼,我先学学laravel。一直做项目,就没做总结
2020-11-10 17:45:17 回复
Lollypop :122
2020-10-05 16:29:16 回复
youyingxiang :```ssss```
2020-09-29 22:56:49 回复
Vip :151515
2020-09-01 13:13:53 回复
youyingxiang :1212
2020-10-04 01:11:04 回复
@ :你好
2020-10-04 01:11:43 回复
youyingxiang :hell
2020-10-04 01:12:51 回复
沙漠狂奔的鱼 :github
2020-08-19 20:35:58 回复
null :表示看的一脸懵逼
2020-07-10 15:14:02 回复
追风筝的人 :https://thekiterunner.com.cn/ 吉朝阳博客 白大神 交换一下友链呗
2020-06-26 23:26:21 回复
仙士可 :
2020-06-26 18:04:21 回复
nm$l :testeeee
2020-06-22 18:13:54 回复
悠闲人1_vag :老哥,有没有PHP的PDF转图片的资料,文档,然后转换图片后加个水印
2020-06-17 15:58:44 回复
:嘀嘀嘀
2020-06-03 22:34:10 回复
wuye251 :滴滴滴滴,打卡
2020-05-27 21:39:10 回复
最新评论