我正在尝试使用下面的代码调用动态创建的Junit测试类
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
URL classUrl = javaClass.getParent().toFile().toURI().toURL();
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { classUrl });
Class<?> clazz = Class.forName(fileName, true, classLoader);
Object obj = clazz.newInstance();
context.getLogger().log("Test Class Loader==>"+obj.getClass().getClassLoader()+"\n");
JUnitCore junit = new JUnitCore();
context.getLogger().log("JUnitCore Class Loader==>"+junit.getClass().getClassLoader()+"\n");
junit.addListener(new TextListener(new PrintStream(outputStream)));
Result result = junit.run(clazz);
return outputStream.toString();
动态创建的测试文件
public class SampleJavaFileTest {
String EXPECTED_OUTPUT_STRING="r3plac3";
@Test
public void testReplaceString() {
SampleJavaFile sample = new SampleJavaFile();
String outputString = sample.replaceString("replace","e","3");
Assert.assertEquals(EXPECTED_OUTPUT_STRING, outputString);
}
}
但是我得到的错误是
There was 1 failure:
1) initializationError(JUnitTest)
org.junit.runners.model.InvalidTestClassError: Invalid test class 'JUnitTest':
1. No runnable methods
at org.junit.runners.ParentRunner.validate(ParentRunner.java:511)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:101)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:84)
at org.junit.runners.JUnit4.<init>(JUnit4.java:23)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder
.runnerForClass(AllDefaultPossibilitiesBuilder.java:37)
at org.junit.runner.Computer.getRunner(Computer.java:50)
at org.junit.runner.Computer$1.runnerForClass(Computer.java:31)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:70)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:125)
at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:111)
at org.junit.runners.Suite.<init>(Suite.java:81)
at org.junit.runner.Computer$2.<init>(Computer.java:33)
我尝试打印动态创建的类和JUnitCore类的类加载器,结果是
Test Class Loader==>java.net.FactoryURLClassLoader@86be70a
JUnitCore Class Loader==>java.net.URLClassLoader@49c2faae
在浏览各种帖子时,提供的答案是使用自定义类加载器来解决此问题。您可以协助创建如何创建自定义类加载器来解决此问题吗?
如果不是自定义类加载器,该如何解决?
谢谢!
答案 0 :(得分:0)
此异常是在此junit代码块中生成的
List<Method> methods = testClass.getAnnotatedMethods(Test.class);
if (methods.size() == 0) {
errors.add(new Exception("No runnable methods"));
}
因此,我建议仔细检查一下,您肯定有方法的注解@Test,它实际上是org.junit.Test,并且此注解在运行时可用。
您可以通过采用klass.getDeclaredMethod(“ testReplaceString”)并从中打印所有注释来进行检查。
如果这没有帮助,则可以调试Junit库,将断点置于异常(请注意,此异常在抛出的位置不同的位置生成)并检查条件
顺便说一句,您使用什么版本的junit?
编辑: 我检查了您的代码,在IDEA中创建了一个新项目,为依赖项添加了junit 4.13-rc-1,并创建了两个文件。
public class SampleJavaFileTest {
String EXPECTED_OUTPUT_STRING="r3plac3";
@Test
public void testReplaceString() {
Assert.assertEquals(EXPECTED_OUTPUT_STRING, "r3plac3");
}
}
和另一个班
public class ClassLoadDynamically {
public static void main(String[] args) throws Exception {
final File fileForClass = new File(SampleJavaFileTest.class.getProtectionDomain().getCodeSource().getLocation().getPath());
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { fileForClass.toURI().toURL() });
Class<?> clazz = Class.forName("SampleJavaFileTest", true, classLoader);
Method testReplaceString = clazz.getDeclaredMethod("testReplaceString");
System.out.println("Get declared methods==>"+ testReplaceString);
System.out.println("Get annotation => "+ testReplaceString.getAnnotation(org.junit.Test.class));
JUnitCore junit = new JUnitCore();
Result result = junit.run(clazz);
System.out.println(result.wasSuccessful());
}
}
我已经检查了您的代码,它以这种方式工作。请检查,如何动态生成代码,看起来像是字节码生成错误的问题,请仔细检查,如何为方法设置注释。
但是,我不确定您在lambda上的环境配置。无论如何,我建议使您的代码在本地运行
答案 1 :(得分:0)
这可能是与类加载器有关的问题,请尝试使用构造函数创建URLClassLoader
并像父类加载器一样传递其他测试类(或只是junit类)的类加载器,以确保始终加载JUnit类由同一个类加载器。并再次检查这是正确的注释,并带有正确的软件包。
public URLClassLoader(URL[] urls, ClassLoader parent)
如此
new URLClassLoader(urlOfToClass, SomeTestOrJUnitClass.class.getClassLoader())