如何从单个 java_test() 规则在 Bazel 中运行所有测试?

Zei*_*ist 9 bazel

我正在 Bazel 中添加测试,但我不想为每个测试文件编写测试规则。但是,每个测试规则都需要一个 test_class - 正在运行的测试类,因此没有简单的方法可以使用单个 java_test 规则运行所有测试。有没有办法解决我不需要指定 test_class 而只需一次运行所有测试的地方?

小智 5

Bazel 中,我们编写了一个自定义 Junit 套件,它可以在带注释的类的包中或包下的类路径上查找所有 Junit 类。您可以在此处找到代码。它非常简短直接,您可以将其复制到您的项目中或执行类似操作。

然后你可以有这样的规则:

java_library(
    name = "tests",
    testonly = 1,
    srcs = glob(["*.java"])
)

java_test(
   name = "MyTests",
   test_class = "MyTests",
   runtime_deps = [":tests"],
)
Run Code Online (Sandbox Code Playgroud)

MyTests.java 文件应如下所示:

import package.ClasspathSuite;

import org.junit.runner.RunWith;

@RunWith(ClasspathSuite.class)
public class MyTests { } 
Run Code Online (Sandbox Code Playgroud)

  • 如何引用依赖项以获取`com.google.devtools.build.lib.testutil.ClasspathSuite`? (4认同)

Ada*_*dam 4

您可以编写一个 JUnit 测试套件类,它将运行您的其他测试。例如,如果您有测试类 Test1.java 和 Test2.java,您可以执行以下操作:

AllTests.java

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class
})
public class AllTests {}
Run Code Online (Sandbox Code Playgroud)

建造

java_test(
    name = "AllTests",
    test_class = "AllTests",
    srcs = [
        "AllTests.java",
        "Test1.java",
        "Test2.java",
    ],
)
Run Code Online (Sandbox Code Playgroud)

编辑回应评论:

如果您不想在测试套件中指定测试类名称,您可以通过反射执行某些操作。以下示例假设所有测试都位于“com.foo”包中,并且所有测试都是 java_test 规则的 src:

package com.foo;

import java.io.File;
import java.io.IOException;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import junit.framework.JUnit4TestAdapter;
import junit.framework.TestSuite;
import org.junit.runner.RunWith;

@RunWith(org.junit.runners.AllTests.class)
public class AllTests {
  public static TestSuite suite() throws IOException {
    TestSuite suite = new TestSuite();
    URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
    // The first entry on the classpath contains the srcs from java_test
    findClassesInJar(new File(classLoader.getURLs()[0].getPath()))
        .stream()
        .map(c -> {
          try {
            return Class.forName(c);
          } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
          }
        })
        .filter(clazz -> !clazz.equals(AllTests.class))
        .map(JUnit4TestAdapter::new)
        .forEach(suite::addTest);
    return suite;
  }

  private static Set<String> findClassesInJar(File jarFile) {
    Set<String> classNames = new TreeSet<>();
    try {
      try (ZipFile zipFile = new ZipFile(jarFile)) {
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
          String entryName = entries.nextElement().getName();
          if (entryName.startsWith("com/foo") && entryName.endsWith(".class")) {
            int classNameEnd = entryName.length() - ".class".length();
            classNames.add(entryName.substring(0, classNameEnd).replace('/', '.'));
          }
        }
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return classNames;
  }
}
Run Code Online (Sandbox Code Playgroud)