Есть ли способ заставить Eclipse запускать JUnit-тест несколько раз до отказа?

У нас иногда появляются ошибки, которые появляются один раз в каждом прогоне X. Прежде чем люди проведут проверку (где это автоматически JUnit'd), наши разработчики должны передать JUnit локально через Eclipse.

Есть ли удобный способ (встроенный или высококачественный плагин), чтобы заставить Eclipse выполнить один и тот же тест X раз и остановиться, если есть сбой? Альтернатива просто нажатию Run X раз?

Обратите внимание, что я что-то искал в пользовательском интерфейсе (например, правой кнопкой мыши и говорю "Запустить X раз", а не просто "Запустить" ).

Ответ 1

Если цикл for работает, то я согласен с nos.

Если вам нужно повторить всю процедуру установки-тестирования, вы можете использовать TestSuite:

  • Щелкните правой кнопкой мыши пакет, содержащий тест, чтобы повторить
  • Перейдите в New и выберите создать JUnit test SUITE
  • Убедитесь, что выбран только те тесты, которые вы хотите повторить, и щелкните по ним, чтобы закончить.
  • Отредактируйте файл для его запуска несколько раз.

В файле вы найдете

addTestSuite(YourTestClass.class)

и оберните это в цикл for.

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

Ответ 2

Если вы действительно хотите запустить тестовый класс до отказа, вам нужен ваш собственный бегун.

@RunWith(RunUntilFailure.class)
public class YourClass {

    // ....

}

который может быть реализован следующим образом...

package com.example;

import org.junit.internal.runners.*;
import org.junit.runner.notification.*;
import org.junit.runner.*;

public class RunUntilFailure extends Runner {

    private TestClassRunner runner;

    public RunUntilFailure(Class<?> klass) throws InitializationError {
        this.runner = new TestClassRunner(klass);
    }

    @Override
    public Description getDescription() {
        Description description = Description.createSuiteDescription("Run until failure");
        description.addChild(runner.getDescription());
        return description;
    }

    @Override
    public void run(RunNotifier notifier) {
        class L extends RunListener {
            boolean fail = false;
            public void testFailure(Failure failure) throws Exception { fail = true; }
        }
        L listener = new L();
        notifier.addListener(listener);
        while (!listener.fail) runner.run(notifier);
    }

}

... освобождение непроверенного кода, чувство вины TDD:)

Ответ 3

Я знаю, что он не отвечает на вопрос напрямую, но если тест не проходит каждый раз, когда он запускается, это тестовый запах, известный как "Исправление теста". Для этого существует несколько возможных причин (из тестовых шаблонов xUnit):

  • Взаимодействующие тесты
  • Взаимодействующие тестовые апартаменты
  • Lonely Test
  • Утечка ресурсов
  • Оптимизм ресурсов
  • Неповторимый тест
  • Test Run War
  • Недетерминированный тест

Подробности каждого из них описаны в главе 16 тестовых шаблонов xUnit.

Ответ 4

Вот сообщение, которое я написал, показывает несколько способов повторного запуска тестов с примерами кода: http://codehowtos.blogspot.com/2011/04/run-junit-test-repeatedly.html

Вы можете использовать бегун @Parametrised или использовать специальный бегун, включенный в сообщение Существует также ссылка на реализацию @Retry

Ответ 5

Основываясь на ответе @akuhn, вот что я придумал - вместо того, чтобы работать навсегда, это будет работать 50 раз или до сбоя, в зависимости от того, что наступит раньше.

package com.foo    

import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

public class RunManyTimesUntilFailure extends Runner {

    private static final int MAX_RUN_COUNT = 50;

    private BlockJUnit4ClassRunner runner;

    @SuppressWarnings("unchecked")
    public RunManyTimesUntilFailure(final Class testClass) throws InitializationError {
        runner = new BlockJUnit4ClassRunner(testClass); 
    }

    @Override
    public Description getDescription() {
        final Description description = Description.createSuiteDescription("Run many times until failure");
        description.addChild(runner.getDescription());
        return description;
    }

    @Override
    public void run(final RunNotifier notifier) {
        class L extends RunListener {
            boolean shouldContinue = true;
            int runCount = 0;

            @Override
            public void testFailure(@SuppressWarnings("unused") final Failure failure) throws Exception {
                shouldContinue = false;
            }

            @Override
            public void testFinished(@SuppressWarnings("unused") Description description) throws Exception {
                runCount++;

                shouldContinue = (shouldContinue && runCount < MAX_RUN_COUNT);
            }
        }

        final L listener = new L();
        notifier.addListener(listener);

        while (listener.shouldContinue) {
            runner.run(notifier);
        }
    }
}

Ответ 6

Я не верю, что в Junit есть встроенный способ сделать именно то, о чем вы просите.

Если несколько запусков приводят к другому результату, вы должны иметь unit test тестирование этого случая. Это может быть так же просто, как запустить цикл for в соответствующих тестовых случаях.

Ответ 7

Можно реализовать такой цикл с помощью TestRule (так как JUnit 4.9)

Очень простая реализация, которая запускает каждый тест 10 раз:

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class SimpleRepeatRule implements TestRule {

    private static class SimpleRepeatStatement extends Statement {

        private final Statement statement;

        private SimpleRepeatStatement(Statement statement) {
            this.statement = statement;
        }

        @Override
        public void evaluate() throws Throwable {
            for (int i = 0; i < 10; i++) {
                statement.evaluate();
            }
        }
    }

    @Override
    public Statement apply(Statement statement, Description description) {
        return new SimpleRepeatStatement(statement);
    }
}

использование:

public class Run10TimesTest {

   @Rule
   public SimpleRepeatRule repeatRule = new SimpleRepeatRule();

   @Test
   public void myTest(){...}
}

Для более полезной реализации на основе аннотации, определяющей, какой метод тестирования должен выполняться, как часто можно посмотреть в этом блоге: http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/