我在Bazel中添加测试,但我不想为每个测试文件编写测试规则。但是,每个测试规则都需要一个test_class - 正在运行的测试类,因此没有简单的方法可以使用单个java_test规则运行所有测试。是否有一个解决方法,我不需要指定test_class并立即运行所有测试?
答案 0 :(得分:4)
在Bazel中,我们编写了一个自定义Junit Suite,它可以在带注释类的包中或包下的类路径中查找所有Junit类。您可以找到代码here。它非常简短直接,你可以将它复制到你的项目或做类似的事情。
然后您可以遵守以下规则:
java_library(
name = "tests",
test_only = 1,
srcs = glob(["*.java"]
)
java_test(
name = "MyTests",
test_class = "MyTests",
runtime_deps = ":tests"
)
并且MyTests.java文件应如下所示:
import package.ClasspathSuite;
import org.junit.runner.RunWith;
@RunWith(ClasspathSuite.class)
public class MyTests { }
答案 1 :(得分:3)
您可以编写一个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 {}
BUILD
java_test(
name = "AllTests",
test_class = "AllTests",
srcs = [
"AllTests.java",
"Test1.java",
"Test2.java",
],
)
编辑回应评论:
如果您不想在测试套件中指定测试类名称,可以通过反射执行某些操作。以下示例假设您的所有测试都在" com.foo"包和所有测试都是java_test规则的srcs:
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;
}
}
答案 2 :(得分:1)
这是一个不需要使用Suite的解决方案。 请记住,它会为每个类单独生成覆盖率报告.dat文件。
.bzl宏来处理所有测试:
def run_tests(name, srcs, package, deps):
for src in srcs:
src_name = src[:-5]
native.java_test(name=src_name, test_class=package + "." + src_name, srcs=srcs, deps=deps, size="small")
从测试文件位置调用该宏:
run_tests(
name = "test",
srcs = glob(["*Test.java"]),
package = "pkg",
deps = [
":src_lib",
]
)
答案 3 :(得分:1)
Gerrit项目包含一个称为junit_tests
的Starlark函数。它获取src列表,并生成一个AllTestsTestSuite.java
文件,该文件在每个Java类中运行测试。它还会生成一个java_test
目标,其中包括生成的Java文件以及所有指定的源,部门等。这是设置方法。
首先将这些行添加到您的WORKSPACE
文件中:
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
# Re-usable building blocks for Bazel build tool
# https://gerrit.googlesource.com/bazlets/
# https://gerrit.googlesource.com/bazlets/+/968b97fa03a9d2afd760f2e8ede3d5643da390d2
git_repository(
name = "com_googlesource_gerrit_bazlets",
remote = "https://gerrit.googlesource.com/bazlets",
commit = "968b97fa03a9d2afd760f2e8ede3d5643da390d2",
)
# We cannot use the tar.gz provided over HTTP because it contains timestamps and each download has a
# different hash.
#http_archive(
# name = "com_googlesource_gerrit_bazlets",
# sha256 = "...",
# urls = [
# "https://gerrit.googlesource.com/bazlets/+archive/968b97fa03a9d2afd760f2e8ede3d5643da390d2.tar.gz",
# ],
#)
# This provides these useful imports:
# load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "maven_jar")
# load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
现在将其添加到您的BUILD
文件中:
load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
junit_tests(
name = "AllTests",
srcs = glob(["*.java"]),
deps = [
"//java/com/company/a_package",
"@maven//:junit_junit",
"@maven//:org_hamcrest_hamcrest",
],
)
如果您的BUILD
文件位于$WORKSPACE_ROOT/javatests/com/company/a_package/BUILD
,则可以使用以下命令运行这些特定测试:
bazel test //javatests/com/company/a_package:AllTests
您可以像这样运行所有Java测试:
bazel test //javatests/...
如果您的目录包含没有测试的.java
文件,则AllTests目标将失败,并显示“没有可运行的方法”。解决方法是将空测试添加到文件中:
/** Workaround for https://github.com/bazelbuild/bazel/issues/2539 */
@Test
public void emptyTest() {}
这对于MacOS上的Bazel 2.0.0来说对我有用。我还可以使用Bazel插件在IntelliJ 2019.2中运行测试。