如何解决编写基于 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 举报,一经查实,本站将立刻删除。