geckoboom / whirlwind-application-testing

whirlwind微框架的功能测试

1.1.1 2023-05-31 11:44 UTC

This package is auto-updated.

Last update: 2024-09-30 01:35:46 UTC


README

应用程序测试检查应用程序所有层(从路由到响应)的集成。它们基于PHPUnit框架,并具有特殊的流程。

  1. 发起请求
  2. 测试响应

需求

  • PHP 7.4 或更高版本。

安装

安装此扩展的首选方式是通过composer。

运行

composer require "geckoboom/whirlwind-application-testing" --dev

或添加

 "geckoboom/whirlwind-application-testing": "*"

到您的composer.json文件的require-dev部分。

定义TestCase

要定义您的REST测试基础设施,您必须创建一个继承自RestTestCase的TestCase类,并实现createApplication()方法的具体实现。

以下代码定义了一个whirlwind应用程序TestCase

<?php

namespace Test;

use League\Container\Container;
use Whirlwind\App\Application\Application;
use WhirlwindApplicationTesting\RestTestCase;
use App\Models\User;

abstract class TestCase extends RestTestCase
{
    protected function createApplication(): Application
    {
        $container = new Container();
        // register service providers here
        return new Application($container);
    }
}

在上面的例子中,我们为进行应用程序测试提供了最小配置

现在您可以进行REST测试。只需创建新的测试并扩展之前创建的TestCase

<?php

namespace Test;

class UsersTest extends TestCase
{
    public function testGetById()
    {   
        $this->addAuthorizationToken('secret')
            ->get('/users/1', ['X-Test-Header' => 'Test'])
            ->assertResponseIsSuccessful()
            ->assertResponseCodeIsOk()
            ->assertHeader('Content-Type', 'application/json')
            ->assertResponseContainsJsonFragment(['id' => 1]);
    }
}

在上面的例子中,测试添加了Bearer授权令牌,并验证HTTP请求是否成功,状态码为200,且响应中包含适当的头和正文片段。

发起请求

TestCase模拟浏览器等HTTP客户端,并向Whirlwind应用程序发起请求。默认情况下,您可以访问以下HTTP方法

  • get($uri, $headers = [])
  • getJson($uri, $headers = [])
  • post($uri, $data = [], $headers = [])
  • postJson($uri, $data = [], $headers = [])
  • put($uri, $data = [], $headers = [])
  • putJson($uri, $data = [], $headers = [])
  • patch($uri, $data = [], $headers = [])
  • patchJson($uri, $data = [], $headers = [])
  • delete($uri, $data = [], $headers = [])
  • deleteJson($uri, $data = [], $headers = [])
  • options($uri, $data = [], $headers = [])
  • optionsJson($uri, $data = [], $headers = [])

如果所需的HTTP方法不在上述列表中,您可以通过call()json()方法发起HTTP请求。

call()json()方法的全签名

call(
    string $method,
    string $uri,
    array $parameters = [],
    array $files = [],
    array $server = [],
    ?string $content = null
)

json(
    string $method,
    string $uri,
    array $parameters = [],
    array $headers = []
)

可用的响应断言

  • assertResponseIsSuccessful()检查状态码是否在[200, 300)范围内
  • assertResponseCodeIs(int $status)检查状态码是否等于$status
  • assertResponseCodeIsOk()检查状态码是否为200
  • assertResponseCodeIsCreated()检查状态码是否为201
  • assertResponseCodeIsAccepted()检查状态码是否为202
  • assertResponseCodeIsNoContent()检查状态码是否为204
  • assertResponseCodeIsBadRequest()检查状态码是否为400
  • assertResponseCodeIsUnauthorized()检查状态码是否为401
  • assertResponseCodeIsForbidden()检查状态码是否为403
  • assertResponseCodeIsNotFound()检查状态码是否为404
  • assertResponseCodeIsNotAllowed()检查状态码是否为405
  • assertResponseCodeIsUnprocessable()检查状态码是否为422
  • assertHeader(string $name, $value = null)检查响应中是否存在名为$name的标头,值是$value(如果非null)
  • assertResponseIsJson()检查响应是否包含有效的JSON
  • assertResponseContains(string $needle, bool $escape = true)检查响应JSON是否包含字符串
  • assertResponseNotContains(string $needle, bool $escape = true)检查响应JSON不包含字符串
  • assertHeaderMissing(string $name)检查响应中是否存在名为$name的标头
  • assertContainsInResponsePath(string $path, $expected)
  • assertResponseContainsExactJson(array $data)
  • assertResponseContainsJsonFragment(array $data) 检查响应是否包含 $data 片段
  • assertResponseNotContainsExactJson(array $data)
  • assertResponseMatchesJsonType(array $jsonSchema, ?string $jsonPath = null) 请参阅 justinrainbow/json-schema
  • assertResponseCount(int $count, ?string $jsonPath = null)

测试用例

测试用例用于将“假”数据集加载到数据库中以进行测试。测试用例可以依赖于其他测试用例(WhirlwindApplicationTesting\Fixture\Fixture::$depends 属性)。

定义测试用例

要定义测试用例,只需创建一个新的类,该类实现 WhirlwindApplicationTesting\Fixture\FixtureInterface

<?php

namespace Test\Fixture;

use Domain\User\User;
use Whirlwind\Infrastructure\Hydrator\UserHydrator;
use Whirlwind\Infrastructure\Repository\TableGateway\UserTableGateway;
use WhirlwindApplicationTesting\Fixture\EntityFixture;

class UserFixture extends EntityFixture
{
    protected string $dataFile = 'users.php';
    protected string $entityClass = User::class;
    
    public function __construct(UserHydrator $hydrator, UserTableGateway $tableGateway) 
    {
        parent::__construct($hydrator, $tableGateway);
    }   
}

提示:每个EntityFixture都是为了准备数据库表以进行测试目的。您可以在构造函数中以及Hydrator实现属性中指定适当的TableGatewayInterface实现。表名封装在表网关中,而Hydrator用于将原始结果映射到WhirlwindApplicationTesting\Fixture\EntityFixture::$entityClass对象

EntityFixture的测试用例数据通常位于声明测试用例类的data目录中的文件中。数据文件应返回要插入表中的数据行数组。例如

<?php

// tests/Fixture/data/users.php
return [
    [
        'name' => 'user1',
        'email' => 'user1@example.org',
        'password' => bcrypt('secret'),
    ],
    [
        'name' => 'user2',
        'email' => 'user2@example.org',
        'password' => bcrypt('secret'),
    ],
];

可以通过指定WhirlwindApplicationTesting\Fixture\Fixture::$depends属性来创建可依赖的测试用例,如下所示

<?php

namespace Test\Fixture;

use Domain\User\UserProfile;
use Whirlwind\Infrastructure\Hydrator\UserHydrator;
use Whirlwind\Infrastructure\Repository\TableGateway\UserTableGateway;
use WhirlwindApplicationTesting\Fixture\EntityFixture;

class UserProfileFixture extends EntityFixture
{
    protected string $dataFile = 'user_profiles.php';
    protected string $entityClass = UserProfile::class;
    protected array $depends = [
        UserFixture::class,
    ];
    
    public function __construct(UserProfileHydrator $hydrator, UserProfileTableGateway $tableGateway) 
    {
        parent::__construct($hydrator, $tableGateway);
    }   
}

依赖关系允许您以良好定义的顺序加载和卸载测试用例。在上面的示例中,UserFixture将始终在UserProfileFixture之前加载。

使用测试用例

如果您在测试代码中使用测试用例,则需要添加 WhirlwindApplicationTesting\Traits\InteractWithFixtures 特性并实现 fixtures() 方法

<?php

namespace Test;

use Domain\Profile\Profile;
use Test\Fixture\UserFixture;
use Test\Fixture\UserProfileFixture;
use WhirlwindApplicationTesting\Traits\InteractWithFixtures;

class UsersTest extends TestCase
{
    use InteractWithFixtures;
    
    public function testGetById()
    {   
        $this->addAuthorizationToken('secret')
            ->get('/users/1', ['X-Test-Header' => 'Test'])
            ->assertResponseIsSuccessful()
            ->assertResponseCodeIsOk()
            ->assertHeader('Content-Type', 'application/json')
            ->assertResponseContainsJsonFragment(['id' => 1]);
    }
    
    public function fixtures(): array
    {
         return [
            'users' => UserFixtureClass::class,
            'profiles' => [
                'class' => UserProfileFixture::class,
                'depends' => [
                    UserFixture::class,
                ],
                'dataFile' => 'profile.php',
                'entityClass' => Profile::class,
            ],
        ];
    }
}

fixtures()方法中列出的测试用例将在执行测试之前自动加载。