You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:26:05