我想使用 PHPUnit 9.6 测试(功能)我的 Symfony 控制器,并且为了不必在每个测试类中具有相同的测试用例,我有想法创建一个包含测试函数的抽象类,然后有一个抽象数据提供者功能。这是我的抽象类:
abstract public function getEndpointConfiguration(): array;
/**
* @dataProvider getEndpointConfiguration
* @testdox It grants access without authentication on endpoint $endpoint and method $method
*/
public function testItGrantsAccessWithoutAuthentication(string $method, string $endpoint, ?string $expectedUserClass): void
{
if ($expectedUserClass !== null) {
static::markTestSkipped();
}
$client = static::createClient();
$client->request($method, $endpoint);
static::assertResponseIsSuccessful();
}
/**
* @dataProvider getEndpointConfiguration
* @testdox It grants access with JWT token to $expectedUserClass on endpoint $endpoint and method $method
*/
public function testItGrantsAccessWithJwtToken(string $method, string $endpoint, ?string $expectedUserClass): void
{
if ($expectedUserClass === null) {
static::markTestSkipped();
}
$client = static::createJwtAuthenticatedClient(
AppFixtures::getUsernameByUserClass($expectedUserClass),
AppFixtures::getPasswordByUserClass($expectedUserClass)
);
$client->request($method, $endpoint);
static::assertResponseIsSuccessful();
}
然后,为了为控制器运行这两个测试,我为扩展我的抽象类的控制器创建一个测试类,并在那里定义抽象函数:
public function getEndpointConfiguration(): array
{
return [
// No authentication required
['GET', '/api/info', null],
// Authentication with User class required
['GET', '/api/me', User::class],
];
}
所以我的想法是提供用户类或 null 作为第三个参数。如果为 null,则应针对该端点执行
testItGrantsAccessWithoutAuthentication
测试,如果它是用户类,则应执行 testItGrantsAccessWithJwtToken
测试。正如您所看到的,我根据提供的第三个参数在两个测试函数中使用了 static::markTestSkipped();
。
问题是我不喜欢在这种情况下测试被标记为跳过。如果完全忽略这些,甚至不影响最终的测试结果就完美了。
一个想法是创建两个单独的 dataProvider,然后传入一个未经身份验证的端点,另一个传入经过身份验证的端点。但是,例如,控制器可能没有未经身份验证的端点,那么您必须在 dataProvider 中为此传递一个空数组,然后在最终结果中会再次跳过测试。
有人对我如何完成这项工作有任何想法吗?
我不确定您是否需要对成功响应进行此类通用测试(这通常会给出错误的支持)。但如果您坚持这种方法,那么同样的一般测试又如何呢:
/**
* @dataProvider getEndpointConfiguration
* @testdox It grants success response on endpoint $endpoint and method $method
*/
public function testEndpoint(string $method, string $endpoint, ?string $expectedUserClass): void
{
$client = $this->getClient($expectedUserClass);
$client->request($method, $endpoint);
static::assertResponseIsSuccessful();
}
private function getClient(?string $expectedUserClass): void
{
if ($expectedUserClass === null) {
return static::createClient();
}
return static::createJwtAuthenticatedClient(
AppFixtures::getUsernameByUserClass($expectedUserClass),
AppFixtures::getPasswordByUserClass($expectedUserClass)
);
}