1、Laravel TDD - 开箱即用的默认测试
系统环境
- Rocky Linux 9.1
- PHP 8.2.3
- Laravel 11.x
- Laravel Installer 5.11.2
TDD 说明
本系列是面向没有使用过驱动测试开发的开发者,使用更加简介高效的 Pest 进行驱动测试开发。
项目使用 Laravel 安装器进行安装,在开始之前请务必安装 Laravel 安装器。
安装项目
$ laravel new pest
┌ Would you like to install a starter kit? ────────────────────┐
│ No starter kit │
└──────────────────────────────────────────────────────────────┘
┌ Which testing framework do you prefer? ──────────────────────┐
│ Pest │
└──────────────────────────────────────────────────────────────┘
默认会生成一个 tests
文件夹,,其中包含 Feature
和 Unit
文件夹,分单是功能测试和单元测试。
功能测试 VS 单元测试
在大数情况下,我们应从功能测试开始,首先测试功能是否正常,而单元测试则着重于单独的、代码单元进行进行,更像是类中的函数一样。
PEST 与 PHPUnit
之前,Laravel 一直使用提 PHP Unit ,但是随着 Pest 愈发简介高效,Laravel 11 使用 Pest 作为功能测试框架,但是,在安装项目时,Laravel 也提供了选择,可以根据自己的喜好来决定使用 Pest 还是 PHP Unit。
它们具有如下特点:
- Pest:简洁,更快,具有一些额外的功能,如架构测试
- PHP Unit:更加标准
运行测试
使用 Pest 编写测试时,每个测试都以函数 test()
或 it()
开头。使用 it()
函数时,Pest 会将其附加到测试的名称中。
现在,让我们看看 tests/Feature
文件夹中的 ExampleTest
。
<?php
it('returns a successful response', function () {
$response = $this->get('/');
$response->assertStatus(200);
});
当我们访问首页时且成功后,将状态断言为 200
,表示请求成功。现在,我们开始测试:
$ php artisan test
PASS Tests\Unit\ExampleTest
✓ that true is true 0.01s
# 这是我们的功能测试
PASS Tests\Feature\ExampleTest
✓ it returns a successful response 0.26s
Tests: 2 passed (2 assertions)
Duration: 0.43s
我们可以看到两个测试成功通过:一个来自 Unit
,一个来自 Feature
测试。
如果测试没有通过会发生什么?我们修改状态来看看。
// tests/Feature/ExampleTest.php
it('returns a successful response', function () {
$response = $this->get('/');
$response->assertStatus(403);
});
测试失败的情况:
]$ php artisan test
PASS Tests\Unit\ExampleTest
✓ that true is true 0.01s
FAIL Tests\Feature\ExampleTest
⨯ it returns a successful response 0.26s
─────────────────────────────────────────────────────────────────────────────────────────────────────────
FAILED Tests\Feature\ExampleTest > it returns a successful response
Expected response status code [403] but received 200.
Failed asserting that 200 is identical to 403.
# 测试失败的情况
at tests/Feature/ExampleTest.php:6
2▕
3▕ it('returns a successful response', function () {
4▕ $response = $this->get('/');
5▕
➜ 6▕ $response->assertStatus(403);
7▕ });
8▕
Tests: 1 failed, 1 passed (2 assertions)
Duration: 0.39s
现在我们可以看到 1 个通过
,1 个失败
。
在里面,我们可以看到哪个测试失败了,在哪个代码行上。它还显示实际错误 Expected response status code [403] but received 200.
。这就是失败的测试的样子。
扩展:PHP Unit 测试
如果使用提 PHP Unit 以该如何编写?
对于 PHPUnit,ExampleTest 是一个扩展 TestCase
的类,每个要测试的测试或功能都是一个函数。
将其与 Pest 进行比较,在 Pest 中,不需要创建类。相反,只需立即编写测试函数。
test 类可以包含多个函数。在每个函数中,执行一些代码,然后测试或断言发生了某些事情以及它是否正确。函数名称应以 test_
前缀开头。下面是默认示例:
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
运行测试
$ php artisan test
PASS Tests\Unit\ExampleTest
✓ that true is true
PASS Tests\Feature\ExampleTest
✓ the application returns a successful response 0.24s
Tests: 2 passed (2 assertions)
Duration: 0.33s
请注意,终端中测试的名称来自函数的命名。在命名 test 函数时,不要害怕使用较长的名称,因为当有人在该功能中启动测试时,这些名称将是可读的。
PHPUnit 测试失败的示例:
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(403);
}
再次进行测试
$ php artisan test
PASS Tests\Unit\ExampleTest
✓ that true is true 0.01s
FAIL Tests\Feature\ExampleTest
⨯ the application returns a successful response 0.24s
─────────────────────────────────────────────────────────────────────────────────────────────────────────
FAILED Tests\Feature\ExampleTest > the application returns a successful response
Expected response status code [403] but received 200.
Failed asserting that 200 is identical to 403.
at tests/Feature/ExampleTest.php:17
13▕ public function test_the_application_returns_a_successful_response(): void
14▕ {
15▕ $response = $this->get('/');
16▕
➜ 17▕ $response->assertStatus(403);
18▕ }
19▕ }
20▕
Tests: 1 failed, 1 passed (2 assertions)
Duration: 0.34s
so easy
TDD 是不是很简单?我们什么都没有做就已经跑起来了。
大多数功能测试只是启动一些页面或调用一些 API,然后测试它是否成功。
如果只是想遍历所有页面或端点并检查它们是否返回 200(或另一个成功消息),这类测试有一个特殊的名字:称为 冒烟测试
。当你刚开始进行测试时,冒烟测试是一个很好的起点。可以在不深入复杂测试语法的情况下,确保你的应用程序在添加新功能后能够正常工作。
接下来关于自动化测试的所有深入主题都是为了探讨不同的断言方法和模拟特定页面或功能场景的方式。这正是我们将在接下来的文章中涵盖的内容。通过这些课程,将学习如何更细致地测试你的应用,确保每个部分都按预期工作。