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

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

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

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

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

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

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

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

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

Ответ 1

Я столкнулся с незначительной проблемой с моим последним решением. Если бы я запускал все тесты из 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");
    }

}

Ответ 2

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

Ответ 3

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

Я могу запустить его из моего кода с помощью:

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

Одним из слабых моментов является то, что он использует соглашение об именах (суффикс "Тест" ) для идентификации тестов. Другой слабой точкой является то, что имя файла 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;
        }
    }

}

Ответ 4

используя класс JUnitCore

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

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

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