如何为自定义PHPStan规则编写无需指定行号的低脆弱性测试
无需指定行号的PHPStan自定义规则测试方案
你可以通过基于代码节点而非行号的断言逻辑解决测试脆弱的问题,核心思路是直接验证违规是否发生在目标方法内,而非依赖固定行号。以下是具体实现方式:
1. 基于AST节点的断言逻辑
利用PHPStan测试框架返回的分析结果,提取违规对应的方法节点,直接验证方法名称是否符合预期:
测试代码示例
use PHPStan\Testing\RuleTestCase; class CustomRuleTest extends RuleTestCase { protected function getRule(): \PHPStan\Rules\Rule { return new CustomRule(); // 你的自定义规则实例 } public function testRule(): void { $testFile = __DIR__ . '/CustomRuleTestData.php'; $analysisResult = $this->analyse([$testFile], [$this->getRule()]); // 从分析结果中提取所有违规对应的方法名 $violatingMethods = array_map(function (\PHPStan\AnalysisError $error) { $node = $error->getNode(); // 确保节点是类方法节点 if ($node instanceof \PhpParser\Node\Stmt\ClassMethod) { return $node->name->toString(); } return null; }, $analysisResult->getErrors()); // 过滤掉非方法节点的违规(如果有的话) $violatingMethods = array_filter($violatingMethods); // 断言预期的方法触发了违规,且无额外违规 $this->assertEqualsCanonicalizing( ['hasViolations', 'hasOtherViolations'], $violatingMethods, '仅预期的方法应触发违规' ); } }
2. 辅助注释标记(可选)
如果需要更精准地标记方法内的违规位置,还可以在测试数据类中添加自定义注释(比如// @expectedViolation),然后在测试中解析这些注释来对比实际违规:
修改后的测试数据类
class CustomRuleTestData { public function hasViolations() { // @expectedViolation 你的规则错误消息内容 // 违规代码逻辑 } public function hasOtherViolations() { // @expectedViolation 你的规则错误消息内容 // 违规代码逻辑 } public function hasNoViolations() { // 合规代码逻辑 } public function hasNoViolationsInAnotherWay() { // 合规代码逻辑 } }
解析注释的测试逻辑
在测试方法中读取测试文件内容,提取所有带有@expectedViolation注释的方法,再和实际违规的方法对比:
// 在testRule方法中添加 $expectedMethods = []; $lines = file($testFile); $currentMethod = null; foreach ($lines as $line) { // 匹配方法定义行 if (preg_match('/public function (\w+)\(/', $line, $matches)) { $currentMethod = $matches[1]; } // 匹配预期违规注释 if ($currentMethod !== null && str_contains($line, '@expectedViolation')) { $expectedMethods[] = $currentMethod; $currentMethod = null; // 避免同一方法多次匹配 } } // 对比预期和实际违规方法 $this->assertEqualsCanonicalizing($expectedMethods, $violatingMethods);
优势说明
- 完全摆脱行号依赖:修改测试类的空行、格式调整、新增测试方法都不会导致测试失败
- 逻辑更直观:直接验证"哪些方法应该违规",而非"哪一行代码应该违规"
- 维护成本更低:重构测试代码时无需同步更新行号配置
内容的提问来源于stack exchange,提问作者Zakaria
相关产品推荐
相关产品推荐

