jolicode / asynit
异步 HTTP 请求测试库,适用于 API 及更多...
Requires
- php: ^8.2
- amphp/amp: ^3.0
- amphp/http-client: ^v5.0.1
- amphp/sync: ^2.0
- bovigo/assert: ^7.0
- symfony/console: ^4.4 || ^5.0 || ^6.0 || ^7.0
- symfony/finder: ^4.4 || ^5.0 || ^6.0 || ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.53.0
- phpstan/phpstan: ^1.10.67
Suggests
- amphp/http-client: To use the web test case trait
Conflicts
- amphp/byte-stream: <2.1
- amphp/http: <2.1
- amphp/http-client: <5.0.1
- symfony/options-resolver: <4.4.30 || <5.3 >= 5.0
README
异步(如果库使用 fiber)测试库运行器,适用于 HTTP / API 及更多...
安装
composer require --dev jolicode/asynit
用法
编写测试
Asynit 将读取 PHP 的类以查找使用 Asynit\Attribute\TestCase
属性的可用测试。您需要在某个目录中创建一个具有 Asynit 的 TestCase
属性的测试类
use Asynit\Attribute\TestCase; #[TestCase] class ApiTest { }
然后您可以添加一些将使用 TestCase 类的 API 的测试
use Asynit\Attribute\Test; use Asynit\Attribute\TestCase; #[TestCase] class ApiTest { #[Test] public function my_test() { // do some test } }
注意:所有测试方法都应该以 test
关键字开头或使用 Asynit\Attribute\Test
注解。其他所有方法将不会自动执行。
测试失败时,如果在测试期间发生异常
使用断言
Asynit 提供了 trait 以简化测试的编写。您可以使用 Asynit\AssertCaseTrait
trait 来使用断言。
use Asynit\Attribute\Test; use Asynit\Attribute\TestCase; #[TestCase] class ApiTest { use Asynit\AssertCaseTrait; #[Test] public function my_test() { $this->assertSame('foo', 'foo'); } }
由于有 bovigo-assert 库的支持,Asynit 支持 PHPUnit 所有的断言。但只要它在失败时抛出异常,您就可以使用自己的断言。
运行测试
要运行此测试,您只需使用此项目提供的 PHP 文件即可
$ php vendor/bin/asynit path/to/the/file.php
如果您有很多测试文件,您可以使用目录运行 Asynit
$ php vendor/bin/asynit path/to/the/directory
使用 HTTP 客户端
Asynit 提供了一个可选的 Asynit\HttpClient\HttpClientWebCaseTrait
trait,您可以使用它来执行 HTTP 请求。您需要安装 amphp/http-client
和 nyholm/psr7
来使用它。
use Asynit\Attribute\TestCase; use Asynit\HttpClient\HttpClientWebCaseTrait; #[TestCase] class FunctionalHttpTests { use HttpClientWebCaseTrait; public function testGet() { $response = $this->get('https//example.com'); $this->assertStatusCode(200, $response); } }
您还可以使用更面向 API 的 trait Asynit\HttpClient\HttpClientApiCaseTrait
,这将允许您编写类似这样的测试
use Asynit\Attribute\TestCase; use Asynit\HttpClient\HttpClientApiCaseTrait; #[TestCase] class FunctionalHttpTests { use HttpClientApiCaseTrait; public function testGet() { $response = $this->get('https//example.com'); $this->assertStatusCode(200, $response); $this->assertSame('bar', $response['foo']); } }
测试之间的依赖关系
有时一个测试可能需要来自另一个测试的结果中的值,例如需要用于某些请求的认证令牌(或定义会话的 cookie)。
Asynit 提供了一个 Depend
属性,允许您指定一个测试依赖于另一个测试。
因此,如果您有 3 个测试,分别是 A
、B
和 C
,并且您说 C
依赖于 A
;则测试 A
和 B
将并行运行,一旦 A
完成且成功,将使用 A
的结果运行 C
。
让我们看一个例子
use Asynit\Attribute\Depend; use Asynit\Attribute\TestCase; use Asynit\HttpClient\HttpClientApiCaseTrait; #[TestCase] class SecurityTest extends TestCase { use HttpClientApiCaseTrait; public function testLogin() { $response = $this->post('/', ['username' => user, 'password' => 'test']); $this->assertStatusCode(200, $response); return $response->getBody()->getContents(); } #[Depend("testLogin")] public function testAuthenticatedRequest(string $token) { $response = $this->get('/api', headers: ['X-Auth-Token' => $token]); $this->assertStatusCode(200, $response); } }
在此处,testAuthenticatedRequest
将仅在 testLogin
完成之后运行。您还可以在不同测试用例之间使用依赖关系。前面的测试用例位于 Application\ApiTest
命名空间下,因此我们可以编写另一个测试用例,如下所示
use Asynit\Attribute\Depend; use Asynit\Attribute\TestCase; use Asynit\HttpClient\HttpClientApiCaseTrait; #[TestCase] class PostTest { #[Depend("Application\ApiTest\SecurityTest::testLogin")] public function testGet($token) { $response = $this->get('/posts', headers: ['X-Auth-Token' => $token]); $this->assertStatusCode(200, $response); } }
测试组织
在许多测试中重用此令牌是很常见的,并且您可能不需要在获取令牌时进行测试。Asynit 允许您依赖于任何类中的任何方法。
因此,您可以编写一个 TokenFetcherClass
来获取令牌,然后在测试中使用它。
namespace App\Tests; use Asynit\HttpClient\HttpClientApiCaseTrait; class TokenFetcher { use HttpClientApiCaseTrait; protected function fetchToken(string $email, string $password = 'password') { $payload = [ 'email' => $email, 'password' => $password, ]; $response = $this->post('/users/token', ['username' => 'user', 'password' => 'test']); return $response['token']; } protected function fetchUserToken() { return $this->fetchToken('email@example.com', 'password'); } }
然后在您的测试类中,您将能够调用此方法
namespace App\Tests; use Asynit\Attribute\Depend; use Asynit\Attribute\TestCase; use Asynit\HttpClient\HttpClientApiCaseTrait; #[TestCase] class OrganizationTest { use HttpClientApiCaseTrait; #[Depend("App\Tests\TokenFetcher::fetchUserToken")] public function test_api_method_with_token(string $token) { $response = $this->get('/api', headers: ['X-Auth-Token' => $token]); // ... } }
如您所见,fetchUserToken
方法不以 test
开头。因此,默认情况下,此方法不会包含在测试套件中。但是,由于它是测试的依赖项,它将作为常规测试包含在全局测试套件中,并利用缓存系统。