如何基于PHPUnit数据提供者参数彻底忽略测试用例?
解决PHPUnit中跳过测试不显示在结果中的问题
问题场景
我使用PHPUnit 9.6对Symfony控制器进行功能测试,为避免在每个测试类中重复编写测试用例,创建了包含测试方法的抽象类及抽象的getEndpointConfiguration数据提供者方法。抽象类的两个测试方法均依赖该数据提供者,通过参数中expectedUserClass是否为null来决定执行逻辑,当前用static::markTestSkipped()跳过不符合的测试,但不希望这些测试出现在结果中。尝试拆分数据提供者的方案仍会因空数组产生跳过测试,现寻求彻底忽略这类测试的可行方法。
现有抽象类代码
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 [ // 无需认证 ['GET', '/api/info', null], // 需要User类认证 ['GET', '/api/me', User::class], ]; }
可行解决方案
方案1:为每个测试方法单独定义过滤后的数据源
在抽象类中新增两个数据提供者方法,分别对getEndpointConfiguration的结果进行过滤,只保留对应测试方法需要的数据集,这样不符合条件的测试用例根本不会生成,自然不会出现在测试结果中。
修改后的抽象类代码:
abstract public function getEndpointConfiguration(): array; /** * 过滤出无需认证的接口配置 * @return array */ public function getPublicEndpointConfiguration(): array { return array_filter($this->getEndpointConfiguration(), function ($dataset) { // 第三个参数为null代表无需认证 return $dataset[2] === null; }); } /** * 过滤出需要JWT认证的接口配置 * @return array */ public function getSecuredEndpointConfiguration(): array { return array_filter($this->getEndpointConfiguration(), function ($dataset) { // 第三个参数不为null代表需要对应用户类的认证 return $dataset[2] !== null; }); } /** * @dataProvider getPublicEndpointConfiguration * @testdox It grants access without authentication on endpoint $endpoint and method $method */ public function testItGrantsAccessWithoutAuthentication(string $method, string $endpoint, ?string $expectedUserClass): void { $client = static::createClient(); $client->request($method, $endpoint); static::assertResponseIsSuccessful(); } /** * @dataProvider getSecuredEndpointConfiguration * @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 { $client = static::createJwtAuthenticatedClient( AppFixtures::getUsernameByUserClass($expectedUserClass), AppFixtures::getPasswordByUserClass($expectedUserClass) ); $client->request($method, $endpoint); static::assertResponseIsSuccessful(); }
方案说明
- 两个新增的数据源方法会自动过滤原始数据,只留下对应测试需要的条目,不会生成多余的测试用例。
- 测试方法无需再写跳过判断逻辑,直接执行核心测试代码即可。
- 控制器测试类无需任何修改,依然只需要实现
getEndpointConfiguration方法。
这样处理后,测试结果中只会显示实际执行的测试用例,完全不会出现被跳过的条目。
内容的提问来源于stack exchange,提问作者Nono
相关产品推荐
相关产品推荐

