执行动态创建的JUnit测试时出错

时间:2019-11-07 08:41:13

标签: java junit reflection aws-lambda

我正在尝试使用下面的代码调用动态创建的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 

在浏览各种帖子时,提供的答案是使用自定义类加载器来解决此问题。您可以协助创建如何创建自定义类加载器来解决此问题吗?

如果不是自定义类加载器,该如何解决?

谢谢!

2 个答案:

答案 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())

https://docs.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html#URLClassLoader(java.net.URL[],%20java.lang.ClassLoader)