web-dev-qa-db-fra.com

java.lang.Exception: aucune exception de méthode exécutable dans l'exécution de JUnits

J'essaie d'exécuter JUnit sur ma commande Linux. L'invite /opt/junit/ contient les fichiers JARS nécessaires (hamcrest-core-1.3.jar et junit.jar) et les fichiers de classe. J'utilise la commande suivante pour exécuter JUnit: 

Java -cp hamcrest-core-1.3.jar:junit.jar:. org.junit.runner.JUnitCore  TestRunner

Classe 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);
   }
}

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());
   }
}  

Je reçois l'exception suivante sur l'exécution de cette

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
37
vipin8169

Vous obtiendrez cette exception si vous utilisez JUnit 4.4 core runner pour exécuter une classe qui n'a pas "@Test" method. Veuillez consulter le lien pour plus d'informations.

courtoisie vipin8169

77
4aRk Kn1gh7

Cette solution s'appliquera à un très petit pourcentage de personnes, généralement celles qui implémentent leurs propres programmes d'exécution de tests JUnit et utilisent un chargeur de classe séparé. 

Cela peut se produire lorsque vous chargez une classe à partir d'un classLoader différent, puis tentez d'exécuter ce test à partir d'une instance de JUnitCore chargée à partir du chargeur de classes système. Exemple:

// 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

En regardant la trace de la pile:

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)

Le problème se produit réellement à BlockJUnit4ClassRunner: 169 (en supposant que JUnit 4.11):

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

Où il vérifie quelles méthodes sont annotées avec @Test:

protected List<FrameworkMethod> computeTestMethods() {
    return getTestClass().getAnnotatedMethods(Test.class);
}

Dans ce cas, Test.class aura été chargé avec le ClassLoader system (c'est-à-dire celui qui a chargé JUnitCore), donc techniquement aucune de vos méthodes de test n'aura été annotée avec cette annotation.

La solution consiste à charger JUnitCore dans le même ClassLoader que les tests eux-mêmes.


Edit: pour répondre à la question de l'utilisateur3486675, vous devez créer un chargeur de classe qui ne délègue pas de délégation au chargeur de classe système, par exemple:

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

Transmettez à cet ensemble d’URLs tout ce dont vous avez besoin. Vous pouvez créer cela en filtrant le chemin d'accès aux classes du système. Notez que vous ne pouvez pas simplement déléguer au ClassLoader parent, car ces classes seraient alors chargées par celui-ci plutôt que par le ClassLoader de vos classes de test.

Ensuite, vous devez lancer l'ensemble du travail JUnit à partir d'une classe chargée par ce classLoader. Cela devient désordonné ici. Quelque chose comme cette immonde souillure ci-dessous:

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));
        }
    }
}

ALORS, vous devez invoquer le coureur par réflexion:

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(...);
14
gubby

Dans mon cas, j'avais le mauvais paquet importé:

import org.testng.annotations.Test;

au lieu de

import org.junit.Test;

Méfiez-vous de votre idée autocomplete.

8
awasik

J'ai eu cette erreur parce que je n'ai pas créé ma propre suite de tests correctement:

Voici comment je l'ai fait correctement:

Mettez ceci dans Foobar.Java:

public class Foobar{
    public int getfifteen(){
        return 15;
    }
}

Mettez ceci dans FoobarTest.Java:

import static org.junit.Assert.*;
import junit.framework.JUnit4TestAdapter;
import org.junit.Test;
public class FoobarTest {
    @Test
    public void mytest() {
        Foobar f = new Foobar();

        assert(15==f.getfifteen());
    }
    public static junit.framework.Test suite(){
       return new JUnit4TestAdapter(FoobarTest.class);
    }
}

Download junit4-4.8.2.jar J'ai utilisé celui d'ici:

http://www.Java2s.com/Code/Jar/j/Downloadjunit4jar.htm

Compilez le:

javac -cp .:./libs/junit4-4.8.2.jar Foobar.Java FoobarTest.Java

Exécuter: 

el@failbox /home/el $ Java -cp .:./libs/* org.junit.runner.JUnitCore FoobarTest
JUnit version 4.8.2
.
Time: 0.009    
OK (1 test)

Un test a réussi.

1
Eric Leschinski

La solution la plus simple consiste à ajouter la méthode annotée @Test à la classe où une exception d'initialisation est présente.

Dans notre projet, nous avons la classe principale avec les paramètres initiaux. J'ai ajouté la méthode @Test et l'exception a disparu.

0
Jackkobec

Dans Eclipse, je devais utiliser New > Other > JUnit > Junit Test. Une classe Java créée avec exactement le même texte m'a donné l'erreur, peut-être parce qu'elle utilisait JUnit 3.x.

0
Noumenon