java.lang.Exception:运行JUnits时没有runnable方法异常

vip*_*169 48 java junit junit4 ubuntu-12.04

我试图在我的Linux命令提示符上运行JUnit /opt/junit/包含必要的JARS(hamcrest-core-1.3.jar和junit.jar)和类文件,我使用以下命令来运行JUnit:

java -cp hamcrest-core-1.3.jar:junit.jar:. org.junit.runner.JUnitCore  TestRunner
Run Code Online (Sandbox Code Playgroud)

TestJunit类:

import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestJunit {
   @Test
   public void testAdd() {
      String str= "Junit is working fine";
      assertEquals("Junit is working fine",str);
   }
}
Run Code Online (Sandbox Code Playgroud)

TestRunner的:

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
   public static void main(String[] args) {
      Result result = JUnitCore.runClasses(TestJunit.class);
      for (Failure failure : result.getFailures()) {
         System.out.println("fail ho gaya"+failure.toString());
      }
      System.out.println("passed:"+result.wasSuccessful());
   }
}  
Run Code Online (Sandbox Code Playgroud)

我在运行它时遇到以下异常

JUnit version 4.11
.E
Time: 0.003
There was 1 failure:
1) initializationError(TestRunner)
java.lang.Exception: No runnable methods
    at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:169)
    at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:104)
    at org.junit.runners.ParentRunner.validate(ParentRunner.java:355)
    at org.junit.runners.ParentRunner.<init>(ParentRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:57)
    at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
    at org.junit.runner.Computer.getRunner(Computer.java:40)
    at org.junit.runner.Computer$1.runnerForClass(Computer.java:31)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:101)
    at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:87)
    at org.junit.runners.Suite.<init>(Suite.java:80)
    at org.junit.runner.Computer.getSuite(Computer.java:28)
    at org.junit.runner.Request.classes(Request.java:75)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
    at org.junit.runner.JUnitCore.runMain(JUnitCore.java:96)
    at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:47)
    at org.junit.runner.JUnitCore.main(JUnitCore.java:40)

FAILURES!!!
Tests run: 1,  Failures: 1
Run Code Online (Sandbox Code Playgroud)

4aR*_*gh7 90

如果使用JUnit 4.4核心运行器来执行没有的类,则会出现此异常"@Test" method. 请咨询该链接以获取更多信息.

礼貌vipin8169

  • 我在使用Junit5时遇到此错误,没有'@Test'我没有任何课程 (12认同)
  • 就我而言,这是由于我的 @Before 方法被命名为 setUp() 而不是 setup() (3认同)

awa*_*sik 22

在我的情况下我导入了错误的包:

import org.testng.annotations.Test;
Run Code Online (Sandbox Code Playgroud)

代替

import org.junit.Test;
Run Code Online (Sandbox Code Playgroud)

小心你的ide自动完成.

  • @wolf97084 是的,`org.junit.Test` = JUnit 4,`org.junit.jupiter.api.Test` = JUnit 5 (5认同)
  • 在我的情况下,它是“ import org.junit.jupiter.api.Test;”。 (2认同)
  • 感谢您节省了我的时间!我也有一个 testng 导入。 (2认同)

gub*_*bby 17

此解决方案适用于极少数人,通常是实现自己的JUnit测试运行器和使用单独的ClassLoader的人.

当您从另一个ClassLoader加载一个类,然后尝试从系统类加载器加载的JUnitCore实例运行该测试时,就会发生这种情况.例:

// Load class
URLClassLoader cl = new URLClassLoader(myTestUrls, null);
Class<?>[] testCls = cl.loadClass("com.gubby.MyTest");

// Run test
JUnitCore junit = new JUnitCore();
junit.run(testCls); // Throws java.lang.Exception: No runnable methods
Run Code Online (Sandbox Code Playgroud)

查看堆栈跟踪:

java.lang.Exception: No runnable methods
at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:169)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:104)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:355)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:57)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
Run Code Online (Sandbox Code Playgroud)

问题实际发生在BlockJUnit4ClassRunner:169(假设JUnit 4.11):

https://github.com/junit-team/junit/blob/r4.11/src/main/java/org/junit/runners/BlockJUnit4ClassRunner.java#L95

在哪里检查哪些方法用注释@Test:

protected List<FrameworkMethod> computeTestMethods() {
    return getTestClass().getAnnotatedMethods(Test.class);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Test.class将加载系统 ClassLoader(即加载JUnitCore的系统),因此从技术上讲,您的测试方法都不会使用该批注进行批注.

解决方案是将JUnitCore加载到与测试本身相同的ClassLoader中.


编辑:在回答user3486675中的问题时,您需要创建一个不委托给系统类加载器的ClassLoader,例如:

private static final class IsolatedURLClassLoader extends URLClassLoader {
    private IsolatedURLClassLoader(URL[] urls) {
        // Prevent delegation to the system class loader.
        super(urls, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

传递一组包含您需要的所有内容的URL.您可以通过过滤系统类路径来创建它.请注意,您不能简单地委托父ClassLoader,因为这些类将由而不是您的测试类的ClassLoader加载.

然后,您需要从此ClassLoader加载的类中启动整个JUnit作业.这里弄得一团糟.这样的东西如下:

public static final class ClassLoaderIsolatedTestRunner {

    public ClassLoaderIsolatedTestRunner() {
        // Disallow construction at all from wrong ClassLoader
        ensureLoadedInIsolatedClassLoader(this);
    }

    // Do not rename.
    public void run_invokedReflectively(List<String> testClasses) throws BuildException {
        // Make sure we are not accidentally working in the system CL
        ensureLoadedInIsolatedClassLoader(this);

        // Load classes
        Class<?>[] classes = new Class<?>[testClasses.size()];
        for (int i=0; i<testClasses.size(); i++) {
            String test = testClasses.get(i);
            try {
                classes[i] = Class.forName(test);
            } catch (ClassNotFoundException e) {
                String msg = "Unable to find class file for test ["+test+"]. Make sure all " +
                        "tests sources are either included in this test target via a 'src' " +
                        "declaration.";
                throw new BuildException(msg, e);
            }
        }

        // Run
        JUnitCore junit = new JUnitCore();
        ensureLoadedInIsolatedClassLoader(junit);
        junit.addListener(...);
        junit.run(classes);
    }

    private static void ensureLoadedInIsolatedClassLoader(Object o) {
        String objectClassLoader = o.getClass().getClassLoader().getClass().getName();

        // NB: Can't do instanceof here because they are not instances of each other.
        if (!objectClassLoader.equals(IsolatedURLClassLoader.class.getName())) {
            throw new IllegalStateException(String.format(
                    "Instance of %s not loaded by a IsolatedURLClassLoader (loaded by %s)",
                    cls, objectClassLoader));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

那么,你需要通过反射来调用跑步者:

Class<?> runnerClass = isolatedClassLoader.loadClass(ClassLoaderIsolatedTestRunner.class.getName());

// Invoke via reflection (List.class is OK because it just uses the string form of it)
Object runner = runnerClass.newInstance();
Method method = runner.getClass().getMethod("run_invokedReflectively", List.class);
method.invoke(...);
Run Code Online (Sandbox Code Playgroud)


sim*_*bac 14

我不得不更改导入语句:

import org.junit.jupiter.api.Test;
Run Code Online (Sandbox Code Playgroud)

import org.junit.Test;
Run Code Online (Sandbox Code Playgroud)


Ren*_*hle 11

我现在在测试代码时遇到了同样的问题。那是由于@RunWith注释在spring boot中引起的。我用过了:

@RunWith(SpringRunner.class)
Run Code Online (Sandbox Code Playgroud)

使用该注释,JUnit Vintage 正在运行,它找不到任何测试并给出错误。我已经删除了它,只有 JUnit Jupiter 正在运行,一切都很好。


小智 11

就我而言,我使用了错误的Test导入。正确的是import org.junit.Test;


小智 8

如果您使用 import org.junit.jupiter.api.Test (Junit 5) 和 @RunWith(SpringRunner.class),SpringRunner 在 Junit4 上,junit 会感到困惑。在类名之前删除 public 将起作用,因为 Junit 5 抱怨公共测试类。来自文档:JUnit5 在测试类的可见性方面比 JUnit4 更宽容,JUnit4 要求所有内容都是公开的。在这种情况下,JUnit5 测试类可以具有除私有之外的任何可见性,但是,建议使用默认的包可见性,这可以提高代码的可读性。


小智 7

就我而言,我只是禁用了 //@RunWith(SpringRunner.class)

无一例外


小智 7

对我来说,import org.junit.jupiter.api.Test;import org.junit.Test;help代替。


小智 5

我的控制器测试非常快捷:

@RunWith(SpringRunner.class)
@SpringBootTest
public class TaskControllerTest {
   //...
   //tests
   //
}
Run Code Online (Sandbox Code Playgroud)

我只是删除了“公共”,然后神奇地起作用了。

  • 这个修复背后的魔力是什么? (3认同)