2010-03-09 9 views
11

Desde Eclipse puedo ejecutar fácilmente todas las pruebas JUnit en mi aplicación.¿Cómo ejecuto programáticamente todas las pruebas JUnit en mi aplicación Java?

Me gustaría poder ejecutar las pruebas en los sistemas de destino desde el jar de la aplicación, sin Eclipse (o Ant o Maven o cualquier otra herramienta de desarrollo).

Puedo ver cómo ejecutar una prueba o suite específica desde la línea de comandos.

Pude crear manualmente un conjunto que incluyera todas las pruebas en mi aplicación, pero parece ser propenso a errores: estoy seguro de que en algún momento voy a crear una prueba y olvidaré agregarla al conjunto.

El complemento JUnit de Eclipse tiene un asistente para crear un conjunto de pruebas, pero por alguna razón no "ve" mis clases de prueba. Puede estar buscando pruebas JUnit 3, no JUnit 4 pruebas anotadas.

Podría escribir una herramienta que crearía automáticamente el paquete escaneando los archivos fuente.

O podría escribir código para que la aplicación escanee su propio archivo jar para las pruebas (ya sea por convención de nombres o buscando la anotación @Test).

Parece que debería haber una manera más fácil. ¿Qué me estoy perdiendo?

Respuesta

4

Me encontré con un problema menor con mi última solución. Si ejecutaba "todas las pruebas" desde Eclipse, se ejecutaban dos veces porque ejecutaban las pruebas individuales Y la suite. Podría haber trabajado en todo eso, pero luego me di cuenta que había una solución más simple:

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

¿Por qué no editas tu publicación anterior entonces, las respuestas múltiples son confusas? – for3st

1

utilizando Clase JUnitCore

JUnitCore es una fachada para la ejecución de pruebas. Es compatible con la ejecución de pruebas JUnit 4, pruebas JUnit 3.8.x y mezclas. Para ejecutar pruebas desde la línea de comandos, ejecute java org.junit.runner.JUnitCore TestClass1 TestClass2 .... Para ejecuciones de prueba one-shot, use el método estático runClasses (Clase []). Si desea agregar escuchas especiales, primero cree una instancia de JUnitCore y úselo para ejecutar las pruebas.

+0

que no resuelve mi problema. Como dije, sé cómo ejecutar clases de prueba específicas desde la línea de comandos. Pero lo que quiero es ejecutar TODAS las pruebas en mi aplicación, sin enumerarlas explícitamente. –

1

no he probado esto hasta el momento, pero se encontró con este blog recientemente: http://burtbeckwith.com/blog/?p=52

El autor proporciona una clase que descubre todas sus junits y los ejecuta, por lo que si ranura de esto en su proyecto fuere proporcionar la capacidad requerida?

Espero que esto ayude.

+0

Descubrí esa publicación antes. El problema es que escanea los archivos fuente. En mis sistemas de destino no tengo la fuente. Sin embargo, podría adaptar su solución para escanear el archivo jar en su lugar. –

4

Basado en http://burtbeckwith.com/blog/?p=52 se me ocurrió lo siguiente. Parece que funciona bien.

que puede ejecutar desde dentro de mi código con:

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

Un punto débil es que se basa en una convención de nomenclatura (sufijo "Test") para identificar las pruebas. Otro punto débil es que el nombre del archivo jar está codificado.

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

¿Podría explicar por qué utiliza el cheque para isAbstract y no otras opciones como isInterface? ¿Los padres abstractos se cargan automáticamente cuando los niños se usan por primera vez? – Hamy

6

Según a recent thread en la lista de correo JUnit, ClasspathSuite puede recoger y ejecutar todas las pruebas JUnit en la ruta de clase.No es precisamente lo que quiere, ya que es una anotación de nivel de clase, pero la fuente está disponible, por lo que puede ampliar su mecanismo de descubrimiento interno.

+0

Gracias, parece que haría lo que quiero, pero probablemente me quedo con mi propia solución, ya que es más simple. –

0

También podría usar ANT que tiene una función incorporada. Escribir una secuencia de comandos ANT y ejecutarla en la máquina de destino. ANT podría crear un informe como resultado.

+0

Sí, pero no quiero instalar ese tipo de herramienta en el sistema de destino. (Como dije en mi pregunta original) –

1

que el proyecto Java y pasar el proyecto

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