2010-03-09 7 views
11

Von Eclipse aus kann ich problemlos alle JUnit-Tests in meiner Anwendung ausführen.Wie programmiere ich programmatisch alle JUnit-Tests in meiner Java-Anwendung?

Ich würde gerne in der Lage sein, die Tests auf Zielsystemen aus der Anwendung jar, ohne Eclipse (oder Ant oder Maven oder andere Entwicklungstool) zu führen.

Ich kann sehen, wie man einen bestimmten Test oder eine Suite von der Kommandozeile aus ausführt.

Ich könnte manuell eine Suite erstellen, die alle Tests in meiner Anwendung auflistet, aber das scheint fehleranfällig - ich bin sicher, irgendwann werde ich einen Test erstellen und vergessen, ihn der Suite hinzuzufügen.

Das Eclipse JUnit Plugin hat einen Assistenten, um eine Testsuite zu erstellen, aber aus irgendeinem Grund "sieht" es meine Testklassen nicht. Es kann nach JUnit 3 Tests suchen, nicht nach JUnit 4 annotierten Tests.

Ich könnte ein Werkzeug schreiben, das automatisch die Suite durch Scannen der Quelldateien erstellen würde.

Oder ich könnte Code schreiben, damit die Anwendung ihre eigene JAR-Datei für Tests scannt (entweder durch Namenskonvention oder durch Suchen nach der @Test-Annotation).

Es scheint, als sollte es einen einfacheren Weg geben. Was vermisse ich?

Antwort

4

Ich stieß auf ein kleines Problem mit meiner letzten Lösung. Wenn ich "alle Tests" von Eclipse ausgeführt habe, liefen sie zweimal, weil sie die einzelnen Tests UND die Suite ausgeführt haben. Ich hätte um das funktionierte, aber dann wurde mir klar, es gab eine einfachere Lösung:

package suneido; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Enumeration; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

public class RunAllTests { 

    public static void run(String jarfile) { 
     String[] tests = findTests(jarfile); 
     org.junit.runner.JUnitCore.main(tests); 
    } 

    private static String[] findTests(String jarfile) { 
     ArrayList<String> tests = new ArrayList<String>(); 
     try { 
      JarFile jf = new JarFile(jarfile); 
      for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) { 
       String name = e.nextElement().getName(); 
       if (name.startsWith("suneido/") && name.endsWith("Test.class") 
         && !name.contains("$")) 
        tests.add(name.replaceAll("/", ".") 
          .substring(0, name.length() - 6)); 
      } 
      jf.close(); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 
     return tests.toArray(new String[0]); 
    } 

    public static void main(String[] args) { 
     run("jsuneido.jar"); 
    } 

} 
+4

Warum bearbeiten Sie nicht Ihren alten Beitrag, mehrere Antworten sind nur verwirrend? – for3st

1

mit Klasse JUnitCore

JUnitCore ist eine Fassade für die Tests ausgeführt werden. Es unterstützt JUnit 4 Tests, JUnit 3.8.x Tests und Mischungen. Um Tests über die Befehlszeile auszuführen, führen Sie java org.junit.runner.JUnitCore TestClass1 TestClass2 ... aus. Verwenden Sie für einmalige Testläufe die statische Methode runClasses (Class []). Wenn Sie spezielle Listener hinzufügen möchten, erstellen Sie zuerst eine Instanz von JUnitCore und verwenden Sie sie, um die Tests auszuführen.

+0

Das ist mein Problem nicht lösen passieren. Wie gesagt, ich weiß, wie man bestimmte Testklassen von der Kommandozeile aus ausführt. Aber was ich will, ist, ALLE Tests in meiner Anwendung auszuführen, ohne jeden explizit aufzuführen. –

1

Ich habe dies als der noch nicht ausprobiert, aber in diesem Blog vor kurzem kam: http://burtbeckwith.com/blog/?p=52

Der Autor stellt eine Klasse, die alle Ihre junits und führt sie entdeckt, so dass, wenn Sie dies in kann es zu einem Projekt Steckplatz Bereitstellung der erforderlichen Fähigkeiten?

Hoffe, das hilft.

+0

Ich hatte diesen Beitrag schon vorher entdeckt. Das Problem ist, dass es die Quelldateien scannt. Auf meinen Zielsystemen habe ich nicht die Quelle. Ich könnte jedoch seine Lösung anpassen, um stattdessen die JAR-Datei zu scannen. –

4

Basierend auf http://burtbeckwith.com/blog/?p=52 kam ich auf Folgendes. Es scheint gut zu funktionieren.

Ich kann es läuft aus meinem Code mit:

org.junit.runner.JUnitCore.main("suneido.AllTestsSuite"); 

Ein Schwachpunkt ist, dass es auf einer Namenskonvention („Test“ Suffix) Tests zur Identifizierung beruht. Ein weiterer Schwachpunkt ist, dass der Name der JAR-Datei fest codiert ist.

package suneido; 

import java.io.IOException; 
import java.lang.reflect.Modifier; 
import java.util.*; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

import org.junit.runner.RunWith; 
import org.junit.runners.Suite; 
import org.junit.runners.model.InitializationError; 

/** 
* Discovers all JUnit tests in a jar file and runs them in a suite. 
*/ 
@RunWith(AllTestsSuite.AllTestsRunner.class) 
public final class AllTestsSuite { 
    private final static String JARFILE = "jsuneido.jar"; 

    private AllTestsSuite() { 
    } 

    public static class AllTestsRunner extends Suite { 

     public AllTestsRunner(final Class<?> clazz) throws InitializationError { 
      super(clazz, findClasses()); 
     } 

     private static Class<?>[] findClasses() { 
      List<String> classFiles = new ArrayList<String>(); 
      findClasses(classFiles); 
      List<Class<?>> classes = convertToClasses(classFiles); 
      return classes.toArray(new Class[classes.size()]); 
     } 

     private static void findClasses(final List<String> classFiles) { 
      JarFile jf; 
      try { 
       jf = new JarFile(JARFILE); 
       for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) { 
        String name = e.nextElement().getName(); 
        if (name.startsWith("suneido/") && name.endsWith("Test.class") 
          && !name.contains("$")) 
         classFiles.add(name.replaceAll("/", ".") 
           .substring(0, name.length() - 6)); 
       } 
       jf.close(); 
      } catch (IOException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     private static List<Class<?>> convertToClasses(
       final List<String> classFiles) { 
      List<Class<?>> classes = new ArrayList<Class<?>>(); 
      for (String name : classFiles) { 
       Class<?> c; 
       try { 
        c = Class.forName(name); 
       } 
       catch (ClassNotFoundException e) { 
        throw new AssertionError(e); 
       } 
       if (!Modifier.isAbstract(c.getModifiers())) { 
        classes.add(c); 
       } 
      } 
      return classes; 
     } 
    } 

} 
+0

Könnten Sie möglicherweise erklären, warum Sie den Check für isAbstract verwenden, und nicht andere Optionen wie isInterface? Werden abstrakte Eltern automatisch geladen, wenn die Kinder zum ersten Mal benutzt werden? – Hamy

6

Nach a recent thread auf der JUnit-Mailingliste können ClasspathSuite sammeln und alle JUnit-Tests auf dem Classpath laufen.Es ist nicht genau das, was Sie wollen, da es sich um eine Annotation auf Klassenebene handelt, die Quelle jedoch verfügbar ist, sodass Sie möglicherweise ihren internen Erkennungsmechanismus erweitern können.

+0

Danke, das sieht so aus, als würde es tun, was ich will, aber ich werde wahrscheinlich bei meiner eigenen Lösung bleiben, da es einfacher ist. –

0

Sie könnten auch verwenden ANT, die integrierte Aufgabe hat. Schreiben Sie ANT-Skript und führen Sie es auf dem Zielcomputer aus. ANT konnte Bericht als Ergebnis erstellen.

+0

Ja, aber ich möchte dieses Tool nicht auf dem Zielsystem installieren. (Wie ich in meiner ursprünglichen Frage gesagt habe.) –

1

das Java-Projekt holen und das Projekt

JUnitLaunchShortcut jUnitLaunchShortcut = new JUnitLaunchShortcut(); 
jUnitLaunchShortcut.launch("Pass the Java Project containing JUnits Classes", "run"); 
Verwandte Themen