запуск подмножества методов JUnit @Test - PullRequest
13 голосов
/ 05 августа 2009

Мы используем JUnit 4 для тестирования: у нас есть классы, которые не являются подклассом TestCase, и у них есть открытые методы, помеченные @Test. У нас есть один файл со многими @Test методами. Было бы неплохо иметь возможность запускать их подмножество из командной строки Ant в стиле этого рецепта для JUnit 3:

ant runtest -Dtest=MyTest -Dtests=testFoo,testBar

http://today.java.net/pub/a/today/2003/09/12/individual-test-cases.html

Я пытался придумать способы достижения этого с помощью отражения Java и т. Д. Поскольку, похоже, нет никакого способа «спрятать» @Test методы или удалить их аннотации во время выполнения, кажется, что единственный вариант использовать метод ClassLoader defineClass, который кажется довольно сложным.

P.S. В этой ситуации правильно было бы разбить файл, но есть ли альтернативы?

Спасибо за ваше время.

Ответы [ 4 ]

13 голосов
/ 02 мая 2011

Начиная с JUnit 4.8 у нас есть аннотации @Category для решения именно этой проблемы.

10 голосов
/ 06 августа 2009

решение Герды это хорошо. Вот что я в итоге сделал (это микс рецепта Люка Франкла, который я связал ранее, и некоторых других вещей, которые я видел в сети):

import org.junit.runner.manipulation.Filter;
import org.junit.runner.Description;

public final class AntCLFilter extends Filter {
    private static final String TEST_CASES = "tests";
    private static final String ANT_PROPERTY = "${tests}";
    private static final String DELIMITER = "\\,";
    private String[] testCaseNames;

    public AntCLFilter() {
        super();
        if (hasTestCases()) testCaseNames = getTestCaseNames();
    }

    public String describe() {
        return "Filters out all tests not explicitly named in a comma-delimited list in the system property 'tests'.";
    }

    public boolean shouldRun(Description d) {
        String displayName = d.getDisplayName();
        // cut off the method name:
        String testName = displayName.substring(0, displayName.indexOf('('));
        if (testCaseNames == null) return true;

        for (int i = 0; i < testCaseNames.length; i++)
            if (testName.equals(testCaseNames[i]))
                return true;
        return false;
    }

    /**
     * Check to see if the test cases property is set. Ignores Ant's
     * default setting for the property (or null to be on the safe side).
     **/
    public static boolean hasTestCases() {
        return
            System.getProperty( TEST_CASES ) == null ||
            System.getProperty( TEST_CASES ).equals( ANT_PROPERTY ) ?
            false : true;
    }

    /**
     * Create a List of String names of test cases specified in the
     * JVM property in comma-separated format.
     *
     * @return a List of String test case names
     *
     * @throws NullPointerException if the TEST_CASES property
     * isn't set
     **/
    private static String[] getTestCaseNames() {

        if ( System.getProperty( TEST_CASES ) == null ) {
            throw new NullPointerException( "Test case property is not set" );
        }

        String testCases = System.getProperty( TEST_CASES );
        String[] cases = testCases.split(DELIMITER);

        return cases;
    }
}

import org.junit.internal.runners.*;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.NoTestsRemainException;

public class FilteredRunner extends TestClassRunner {

    public FilteredRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
        Filter f = new AntCLFilter();
        try {
            f.apply(this);
        } catch (NoTestsRemainException ex) {
            throw new RuntimeException(ex);
        }
    }
}

Затем я прокомментировал свой тестовый класс:

@RunWith(FilteredRunner.class)
public class MyTest {

и поместите в мой сборочный файл ant следующее:

<target name="runtest"
        description="Runs the test you specify on the command line with -Dtest="
        depends="compile, ensure-test-name">
    <junit printsummary="withOutAndErr" fork="yes">
        <sysproperty key="tests" value="${tests}" />
        <classpath refid="classpath" />
        <formatter type="plain" usefile="false" />
        <batchtest>
            <fileset dir="${src}">
                <include name="**/${test}.java" />
            </fileset>
        </batchtest>
    </junit>
</target>

ключевая строка для тега sysproperty.

А теперь я могу бежать

ant runtest -Dtest=MyTest -Dtests=testFoo,testBar

по желанию. Это работает с JUnit 4.1 --- в 4.4, подкласс от JUnit4ClassRunner, и в 4.5 и позже, подкласс от BlockJUnit4ClassRunner.

8 голосов
/ 05 августа 2009

Создайте свой собственный TestClassMethodsRunner (он не задокументирован, или я его сейчас не нахожу).
A TestClassMethodsRunner выполняет все тестовые случаи, и вы можете настроить отфильтрованный TestClassMethodsRunner.

Все, что вам нужно сделать, это переопределить метод TestMethodRunner createMethodRunner(Object, Method, RunNotifier). Это простое хакерское решение:

public class FilteredTestRunner extends TestClassMethodsRunner {

    public FilteredTestRunner(Class<?> aClass) {
        super(aClass);
    }

    @Override
    protected TestMethodRunner createMethodRunner(Object aTest, Method aMethod, RunNotifier aNotifier) {
        if (aTest.getClass().getName().contains("NOT")) {
            return new TestMethodRunner(aTest, aMethod, aNotifier, null) {
                @Override
                public void run() {
                    //do nothing with this test.
                }
            };
        } else {
            return super.createMethodRunner(aTest, aMethod, aNotifier);
        }
    }

}

С помощью этого TestRunner вы выполняете все тесты, которые не содержат строку «NOT». Другие будут игнорироваться :) Просто добавьте аннотацию @RunWith с вашим классом TestRunner к вашему тесту.

@RunWith(FilteredTestRunner.class)
public class ThisTestsWillNOTBeExecuted {
   //No test is executed.
}

@RunWith(FilteredTestRunner.class)
public class ThisTestsWillBeExecuted {
   //All tests are executed.
}

В методе createMethodRunner вы можете сравнить текущий тест со списком тестов, которые должны быть выполнены, или ввести новые критерии.

Удачи с этим!

Подсказки для лучшего решения приветствуются!

1 голос
/ 14 октября 2012

Существует более простой способ для общего случая, когда вам нужно запустить только один метод тестирования, без необходимости создавать пользовательские Runner или Filter:

public class MyTestClass {

  public static void main(final String[] args) throws Exception {
    final JUnitCore junit = new JUnitCore();
    final String singleTest = // Get the name of test from somewhere (environment, system property, whatever you want).
    final Request req;
    if (singleTest != null) {
      req = Request.method(MyTestClass.class, singleTest);
    } else {
      req = Request.aClass(MyTestClass.class);
    }
    final Result result = junit.run(req);
    // Check result.getFailures etc.
    if (!result.wasSuccessful()) {
      System.exit(1);
    }
  }

  // Your @Test methods here.

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...