微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

编写基于 SonarQube Java 的规则来检查 assertj 错误,无法弄清楚何时不调用链式方法

如何解决编写基于 SonarQube Java 的规则来检查 assertj 错误,无法弄清楚何时不调用链式方法

我在一家使用 SonarQube 7.9.2 的大型企业工作。我看到很多错误地使用 AssertJ 框架的测试代码。我看到 SonarSource 确实有一些关于 AssertJ 的规则,但它们都没有涵盖我正在研究的特定问题。

以下是一个示例(我的测试输入之一),显示了我正在寻找的模式:

import static org.assertj.core.api.Assertions.*;

public class assertthatWithnopredicate {

    public Foo foo  = new Foo();

    @Test
    public void assertSomething() throws Exception {
        assertthat(foo.getStuff().equals("abc"));
    }

    public static class Foo {
        private String stuff;

        public String getStuff() { return stuff; }
        public void setStuff(String aStuff) { this.stuff = stuff; }
    }
}

上面的断言是有缺陷的,因为它需要这样做:

assertthat(foo.getStuff()).isEqualTo("abc");

因此,我开始尝试编写一个基于 Java 的 SonarQube 规则来检查这一点。有这方面的文档,但它没有我想要的那么深入。它有几个例子,但它并没有真正详细解释api。我从 https://github.com/SonarSource/sonar-java/blob/master/docs/CUSTOM_RULES_101.md 开始。

以下是我目前对自定义规则的看法。它不能正常工作。我将进一步讨论失败的内容

package org.sonar.samples.java.checks;

import org.sonar.check.Rule;
import org.sonar.plugins.java.api.JavaFileScanner;
import org.sonar.plugins.java.api.JavaFileScannerContext;
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
import org.sonar.plugins.java.api.tree.ImportTree;
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.Tree.Kind;

@Rule(key = "assertthatLackingPredicateCheck",name = "Call to assertthat method has to have at least one chained predicate method call",description = "The AssertJ assertthat method has to have at least one chained predicate method called on the return value,or it does nothing",priority = org.sonar.check.Priority.MAJOR,tags = {"bug"})
public class assertthatLackingPredicateCheck extends BaseTreeVisitor implements JavaFileScanner {

    private JavaFileScannerContext context;

    @Override
    public void scanFile(JavaFileScannerContext context) {
        this.context = context;

        scan(context.getTree());
    }

    @Override
    public void visitImport(ImportTree tree) {
        //scan(tree.qualifiedIdentifier());
        System.out.println("ident[" + tree.qualifiedIdentifier() + "]");
        super.visitImport(tree);
    }

    @Override
    public void visitMemberSelectExpression(MemberSelectExpressionTree tree) {
        System.out.println("In visitMemberSelectExpression.");
        scan(tree.annotations());
        System.out.println("tree.expression.firstToken[" + tree.expression().firstToken().text() + "]");
        scan(tree.expression());
        scan(tree.identifier());
        System.out.println("Exiting visitMemberSelectExpression.");
    }

    @Override
    public void visitMethodInvocation(MethodInvocationTree tree) {
        System.out.println("In visitMethodInvocation.");
        System.out.println("methodSelect[" + tree.methodSelect().firstToken().text() +
                           "] kind[" + tree.methodSelect().kind() +
                           "] parent.kind[" + tree.parent().kind() +
                           "]");
        scan(tree.methodSelect());
        scan(tree.typeArguments());
        scan(tree.arguments());
        if (tree.methodSelect().firstToken().text().equals("assertthat") &&
            tree.methodSelect().kind() == Kind.IDENTIFIER &&
            tree.parent().kind() == Kind.EXPRESSION_STATEMENT) {
            System.out.println("Reporting issue.");
            context.reportIssue(this,tree,"Calls to assertthat have to chain predicate method calls,or the assertion does nothing.");
        }
        System.out.println("Exiting visitMethodInvocation.");
    }
}

我的测试类是这样的:

package org.sonar.samples.java.checks;

import org.junit.jupiter.api.Test;
import org.sonar.java.checks.verifier.JavaCheckVerifier;

public class assertthatLackingPredicateCheckTest {
    @Test
    public void assertthatWithnopredicate() throws Exception {
        JavaCheckVerifier.newVerifier()
            .onFile("src/test/files/assertthatWithnopredicate.java")
            .withCheck(new assertthatLackingPredicateCheck())
            .verifyIssues();
    }

    @Test
    public void assertthatWithValidPredicate() throws Exception {
        JavaCheckVerifier.newVerifier()
            .onFile("src/test/files/assertthatWithValidPredicate.java")
            .withCheck(new assertthatLackingPredicateCheck())
            .verifyNoIssues();
    }
}

一个测试文件包含在上面。第二个是这样的:

import static org.assertj.core.api.Assertions.*;

public class assertthatWithValidPredicate {
    public Foo foo  = new Foo();

    @Test
    public void assertSomething() throws Exception {
        assertthat(foo.getStuff()).isEqualTo("abc");
    }

    public static class Foo {
        private String stuff;

        public String getStuff() { return stuff; }
        public void setStuff(String aStuff) { this.stuff = stuff; }
    }
}

当我运行它时,“有效”测试实际上通过了,但考虑到我并不真正了解我正在使用的 api,这很可能是巧合。

“无效”测试失败并显示奇怪的堆栈跟踪:

java.lang.AssertionError: Unexpected at [10]
    at org.sonar.java.testing.InternalCheckVerifier.assertMultipleIssues(InternalCheckVerifier.java:308)
    at org.sonar.java.testing.InternalCheckVerifier.checkIssues(InternalCheckVerifier.java:232)
    at org.sonar.java.testing.InternalCheckVerifier.verifyAll(InternalCheckVerifier.java:223)
    at org.sonar.java.testing.InternalCheckVerifier.verifyIssues(InternalCheckVerifier.java:168)
    at org.sonar.samples.java.checks.assertthatLackingPredicateCheckTest.assertthatWithnopredicate(assertthatLackingPredicateCheckTest.java:12)

我还要指出,这不是我第一次尝试解决这个问题,而是几年前,并且使用 AssertJ 所基于的旧框架解决测试问题。当时,我为此开发了一个 XPath 规则,它实际上似乎有效。不幸的是,我无法将 XPath 规则集成到我们的 SonarQube 实例中,只能使用基于 Java 的规则。

旧线程在这里http://sonarqube-archive.15.x6.nabble.com/Write-a-custom-XPath-task-that-looks-for-a-method-that-is-NOT-followed-by-a-chained-method-call-td5024017.html。响应确实尝试了可能的基于 Java 的解决方案,但我不太明白他的说明。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。