繁体   English   中英

SonarQube测试自定义Java规则无法显示语义信息

[英]SonarQube Test Custom Java Rule fails to display semantic information

我正在学习SonarQube的API,试图扩展java插件规则。 我成功地遵循了本教程

现在我想构建一个简单的分析,检查单元测试中是否使用了toString()方法。

public class TS_SensitiveEqualityCheck extends BaseTreeVisitor implements JavaFileScanner {

  private final Deque<Boolean> methodContainsToStringInAssert = new ArrayDeque<Boolean>();
  private final Deque<Boolean> inUnitTest = new ArrayDeque<Boolean>();

  private JavaFileScannerContext context;

  @Override
  public void scanFile(final JavaFileScannerContext context) {
    this.context = context;
    scan(context.getTree());
  }

  @Override
  public void visitMethod(MethodTree methodTree) {
    if (ModifiersUtils.hasModifier(methodTree.modifiers(), Modifier.ABSTRACT)) {
      return;
    }
    boolean isUnitTest = isUnitTest(methodTree);
    inUnitTest.push(isUnitTest);
    System.out.println("For method " + methodTree.simpleName() 
    + " found [isUnitTest | isViolation] :  " 
    + String.valueOf(isUnitTest));
    methodContainsToStringInAssert.push(false);
    super.visitMethod(methodTree);
    inUnitTest.pop();
    Boolean isViolation = methodContainsToStringInAssert.pop();
    System.out.println("For method " + methodTree.simpleName() 
            + " found [isUnitTest | isViolation] :  " 
            + String.valueOf(isUnitTest) + " " 
            + String.valueOf(isViolation) );
    if (isUnitTest && isViolation) { 
      context.reportIssue(this, methodTree.simpleName(), "This test method uses unsafe equality checking!");
    }
  }

  @Override
  public void visitMethodInvocation(MethodInvocationTree mit) {
    if (!inUnitTest()) {
      return;
    }
    Symbol mis = mit.symbol();
    System.out.println(mis.name()); // null when encountering an assertion.
    if (mis.name() != null && mis.name().equals("toString")) {
        setTrue(methodContainsToStringInAssert);
    }
    super.visitMethodInvocation(mit);
  }

  private boolean inUnitTest() {
    return !inUnitTest.isEmpty() && inUnitTest.peek();
  }

  private static void setTrue(Deque<Boolean> collection) {
    if (collection != null && !collection.peek()) {
      collection.pop();
      collection.push(true);
    }
  }

  private static boolean isUnitTest(MethodTree methodTree) {
    JavaSymbol.MethodJavaSymbol symbol = (JavaSymbol.MethodJavaSymbol) methodTree.symbol();
    while (symbol != null) {
      if (symbol.metadata().isAnnotatedWith("org.junit.Test")) {
        return true;
      }
      symbol = symbol.overriddenSymbol();
    }
    Symbol.TypeSymbol enclosingClass = methodTree.symbol().enclosingClass();
    return (enclosingClass != null 
            // && enclosingClass.type().isSubtypeOf("junit.framework.TestCase")  // errors!!! does not get the package name of the class!!!
            && methodTree.simpleName().name().startsWith("test"));
  }

}

对于给定的测试文件,SonarQube找不到任何断言方法调用! 只有方法B.is()给出一个结果,即mit.symbol().name != null 谁能解释为什么会出错? 这是用作测试的文件:

import junit.framework.TestCase;
    import javax.annotation.Nullable;

public class AssertionsInTestsCheckTestJunit3 extends TestCase { public void testCompliant() { B b = new B(); b.is(); org.junit.Assert.assertTrue(b.is()); } public void testNoncompliant() { // Noncompliant org.junit.Assert.assertTrue(this.toString().equals("")); } public void testNoncompliant2() { // Noncompliant org.junit.Assert.assertEquals(this.toString(), ""); } public void testNoncompliant3() { // Noncompliant org.junit.Fail.fail(this.toString()); doWork(); } @Nullable public Test notAtest() { compliant1(); } } public class B { public boolean is() { return true; } } </pre></code>

请注意,此代码的作用并不重要!

Java Analyzer需要源文件中使用的库的字节代码才能完成语义模型。 没有它,大多数可以检索的语义信息都会丢失。

在您的测试文件中,您使用的是junit 但是,缺少与junit相关的二进制文件,因为您很可能不会向检查验证程序提供库。 该部分尚未在教程中描述。

默认情况下,没有为检查验证程序提供外部库,因为教程在当前状态下不需要外部库。 解释如何使用外部源的部分尚未编写,但一旦完成,它应该可以通过以下链接获得: 如何测试需要外部二进制文件的源

现在,为了解决您的问题并总结教程中将要呈现的内容,您需要执行以下操作:

为了在分析文件时使用足够的字节代码,您必须向check checkifier提供junit二进制文件 有多种方法可以做到这一点,但最简单的方法可能是将jar放在项目的专用位置: target/test-jars 默认情况下,检查验证程序将查找此文件夹。

您可以通过更改项目根目录下的pom.xml文件来自动添加任何所需的库:

  1. 在插件根目录的pom.xml文件中,您应该看到一个注释部分: pom.xml#L108 (来自教程中使用的模板)
  2. 取消评论此部分代码。 请注意,对于该示例,它已包含apache commons-collections的二进制文件。
 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.10</version>
    <executions>
      <execution>
        <id>copy</id>
        <phase>test-compile</phase>
        <goals>
          <goal>copy</goal>
        </goals>
        <configuration>
          <artifactItems>
            <artifactItem>
              <groupId>org.apache.commons</groupId>
              <artifactId>commons-collections4</artifactId>
              <version>4.0</version>
              <type>jar</type>
            </artifactItem>
          </artifactItems>
          <outputDirectory>${project.build.directory}/test-jars</outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>
  1. 替换<artifactItem>代替使用junit,或者只是添加一个新工件:
  <artifactItem>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <type>jar</type>
  </artifactItem>
  1. 使用mvn clean install -DskipTests重新构建项目。 具有所需版本的junit jar将由maven下载,并放在target/test-jars文件夹中。

  2. 重新运行测试。 应该检测问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM