2010-03-09 5 views
11

Из Eclipse я могу легко запустить все тесты JUnit в своем приложении.Как программно запускать все тесты JUnit в приложении Java?

Я хотел бы иметь возможность запускать тесты на целевых системах из приложения, без Eclipse (или Ant или Maven или любого другого инструмента разработки).

Я могу увидеть, как запустить конкретный тест или набор из командной строки.

Я мог бы вручную создать набор, содержащий все тесты в моем приложении, но это кажется склонным к ошибкам - я уверен, что в какой-то момент я создам тест и забуду добавить его в пакет.

В плагине Eclipse JUnit есть мастер для создания набора тестов, но по какой-то причине он не «видит» мои тестовые классы. Он может искать тесты JUnit 3, а не аннотированные тесты JUnit 4.

Я мог бы написать инструмент, который автоматически создавал бы пакет, сканируя исходные файлы.

Или я мог бы написать код, чтобы приложение сканировало собственный файл jar для тестов (либо по соглашению об именах, либо в поисках аннотации @Test).

Кажется, что должен быть более простой способ. Что мне не хватает?

ответ

4

У меня возникла небольшая проблема с моим последним решением. Если бы я запускал все тесты из Eclipse, они запускались дважды, потому что они запускали отдельные тесты и набор. Я мог бы работать вокруг этого, но потом я понял, что есть простое решение:

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

Почему бы не изменить свой старый пост, несколько ответов просто запутывают? – for3st

1

с использованием класса JUnitCore

JUnitCore фасадная для выполнения тестов. Он поддерживает запуск тестов JUnit 4, тестов JUnit 3.8.x и смесей. Для запуска тестов из командной строки запустите java org.junit.runner.JUnitCore TestClass1 TestClass2 .... Для однократных тестовых запусков используйте статический метод runClasses (Class []). Если вы хотите добавить специальные слушатели, сначала создайте экземпляр JUnitCore и используйте его для запуска тестов.

+0

Это не решает мою проблему. Как я уже сказал, я знаю, как запускать определенные тестовые классы из командной строки. Но я хочу запустить ВСЕ тесты в своем приложении, без явного перечисления каждого из них. –

1

Я не пробовал это, до сих пор, но наткнулся на этот блог в последнее время: http://burtbeckwith.com/blog/?p=52

Автор предоставляет класс, который обнаруживает все junits и запускает их, так что если вы слот это в свой проект он может обеспечить необходимую возможность?

Надеюсь, это поможет.

+0

Я обнаружил это сообщение раньше. Проблема в том, что он сканирует исходные файлы. На моих целевых системах у меня нет источника. Однако, возможно, я смогу адаптировать его решение для сканирования файла jar. –

4

Основано на http://burtbeckwith.com/blog/?p=52 Я придумал следующее. Кажется, это хорошо работает.

я могу запустить его в моем коде с:

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

Одно слабое место в том, что она опирается на именовании («Test» суффикс), чтобы идентифицировать тесты. Другим слабым моментом является то, что имя файла jar жестко закодировано.

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

Не могли бы вы объяснить, почему вы используете проверку для isAbstract, а не другие параметры, такие как isInterface? Автоматически загружаются ли абстрактные родители, когда дети используются в первый раз? – Hamy

6

Согласно a recent thread в списке рассылки JUnit, ClasspathSuite может собрать и запустить все тесты JUnit на пути к классам.Это не то, что вы хотите, так как это аннотация на уровне класса, но источник доступен, поэтому вы можете расширить свой механизм внутреннего обнаружения.

+0

Спасибо, похоже, что он будет делать то, что я хочу, но я, вероятно, придерживаюсь своего собственного решения, поскольку он проще. –

0

Вы также можете использовать ANT, который имеет встроенную задачу. Запишите сценарий ANT и запустите его на целевой машине. ANT может создать отчет как результат.

+0

Да, но я не хочу устанавливать такой инструмент в целевой системе. (Как я сказал в моем первоначальном вопросе.) –

1

Получить проект Java и передать проект

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