it-roy-ru.com

Простой способ запустить один и тот же тест джунта снова и снова?

Как видно из заголовка, я ищу простой способ запуска тестов JUnit 4.x несколько раз подряд с использованием Eclipse.

Примером будет запускать один и тот же тест 10 раз подряд и сообщать результат.

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

Идеальным решением будет плагин/настройка/функция Eclipse, о которой я не знаю.

89
Stefan Thyberg

Самый простой (как минимум, требуется новый код) способ сделать это - запустить тест как параметризованный тест (аннотировать с помощью @RunWith(Parameterized.class) и добавить метод для предоставления 10 пустых параметров). Таким образом, фреймворк будет проходить тест 10 раз.

Этот тест должен быть единственным тестом в классе, или, лучше сказать, все методы теста должны быть выполнены в классе 10 раз.

Вот пример:

@RunWith(Parameterized.class)
public class RunTenTimes {

    @Parameterized.Parameters
    public static Object[][] data() {
        return new Object[10][0];
    }

    public RunTenTimes() {
    }

    @Test
    public void runsTenTimes() {
        System.out.println("run");
    }
}

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

Если вы внедряете своего собственного бегуна, он может запустить тест 10 раз. Если вы используете сторонний бегун, то с 4.7 вы можете использовать новую аннотацию @Rule и реализовать интерфейс MethodRule, чтобы он принимал оператор и выполнял его 10 раз в цикле for. Недостаток этого подхода в настоящее время заключается в том, что @Before и @After запускаются только один раз. Скорее всего, это изменится в следующей версии JUnit (@Before будет запускаться после @Rule), но независимо от того, что вы будете действовать на тот же экземпляр объекта (что не так для бегуна Parameterized). Это предполагает, что любой бегун, с которым вы запускаете класс, правильно распознает аннотации @Rule. Это только в том случае, если он делегирует участникам JUnit.

Если вы работаете с пользовательским бегуном, который не распознает аннотацию @Rule, то вам действительно нужно написать свой собственный бегун, который соответствующим образом делегирует этому бегуну и запускает его 10 раз.

Обратите внимание, что есть и другие способы решения этой проблемы (например, бегун Теорий), но все они требуют бегуна. К сожалению, в настоящее время JUnit не поддерживает слои бегунов. Это бегун, который связывает других бегунов.

111
Yishai

Я обнаружил, что повторная аннотация Spring полезна для такого рода вещей: 

@Repeat(value = 10)

Последний (Spring Framework 4.3.11.RELEASE API) документация:

57
laura

С IntelliJ вы можете сделать это из тестовой конфигурации. После того, как вы откроете это окно, вы можете запустить тест сколько угодно раз.

 enter image description here

когда вы запускаете тест, intellij выполнит все тесты, которые вы выбрали для указанного вами количества раз.

Пример выполнения 624 тестов 10 раз:  enter image description here

48
smac89

Вдохновленный на это решение :

Используйте аннотацию @Repeat так:

public class MyTestClass {

    @Rule
    public RepeatRule repeatRule = new RepeatRule();

    @Test
    @Repeat(10)
    public void testMyCode() {
        //your test code goes here
    }
}

Вам понадобятся только эти два класса:

Repeat.Java:

import static Java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static Java.lang.annotation.ElementType.METHOD;
import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;
import Java.lang.annotation.Target;

@Retention( RetentionPolicy.RUNTIME )
@Target({ METHOD, ANNOTATION_TYPE })
public @interface Repeat {
    int value() default 1;
}

RepeatRule.Java:

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

public class RepeatRule implements TestRule {

    private static class RepeatStatement extends Statement {
        private final Statement statement;
        private final int repeat;    

        public RepeatStatement(Statement statement, int repeat) {
            this.statement = statement;
            this.repeat = repeat;
        }

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

    }

    @Override
    public Statement apply(Statement statement, Description description) {
        Statement result = statement;
        Repeat repeat = description.getAnnotation(Repeat.class);
        if (repeat != null) {
            int times = repeat.value();
            result = new RepeatStatement(statement, times);
        }
        return result;
    }
}

2016-10-25 Редактировать: Чтобы использовать это решение при использовании @RunWith(PowerMockRunner.class), обновите до Powermock 1.6.5 (включая этот патч) ,.

30
R. Oosterholt

С помощью JUnit 5 мне удалось решить эту проблему с помощью @RepeatedTest annotation:

@RepeatedTest(10)
public void testMyCode() {
    //your test code goes here
}

Обратите внимание, что аннотация @Test не должна использоваться вместе с @RepeatedTest.

18
César Alberca

Что-то не так с:

@Test
void itWorks() {
    // stuff
}

@Test
void itWorksRepeatably() {
    for (int i = 0; i < 10; i++) {
        itWorks();
    }
}

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

Не нужно делать в конфигурации или аннотации то, что вы можете сделать в коде.

10
soru

В библиотеке tempus-fugit / есть прерывистая аннотация, которая работает с @Rule в JUnit 4.7 для повторения теста несколько раз или с @RunWith.

Например,

@RunWith(IntermittentTestRunner.class)
public class IntermittentTestRunnerTest {

   private static int testCounter = 0;

   @Test
   @Intermittent(repition = 99)
   public void annotatedTest() {
      testCounter++;
   }
}

После запуска теста (с IntermittentTestRunner в @RunWith) testCounter будет равен 99.

7
Toby

Это работает намного проще для меня. 

public class RepeatTests extends TestCase {

    public static Test suite() {
        TestSuite suite = new TestSuite(RepeatTests.class.getName());

        for (int i = 0; i < 10; i++) {              
        suite.addTestSuite(YourTest.class);             
        }

        return suite;
    }
}
7
Qualk

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

https://github.com/anderson-marques/concurrent-testing

Maven зависимость:

<dependency>
    <groupId>org.lite</groupId>
    <artifactId>concurrent-testing</artifactId>
    <version>1.0.0</version>
</dependency>

Пример использования:

package org.lite.concurrent.testing;

import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import ConcurrentTest;
import ConcurrentTestsRule;

/**
 * Concurrent tests examples
 */
public class ExampleTest {

    /**
     * Create a new TestRule that will be applied to all tests
     */
    @Rule
    public ConcurrentTestsRule ct = ConcurrentTestsRule.silentTests();

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 20, threads = 10)
    public void testConcurrentExecutionSuccess(){
        Assert.assertTrue(true);
    }

    /**
     * Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
     */
    @Test
    @ConcurrentTest(requests = 200, threads = 10, timeoutMillis = 100)
    public void testConcurrentExecutionSuccessWaitOnly100Millissecond(){
    }

    @Test(expected = RuntimeException.class)
    @ConcurrentTest(requests = 3)
    public void testConcurrentExecutionFail(){
        throw new RuntimeException("Fail");
    }
}

Это проект с открытым исходным кодом. Не стесняйтесь улучшать. 

0
Anderson Marques

Вы можете запустить свой тест JUnit из основного метода и повторять его столько раз, сколько вам нужно:

package tests;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.Result;

public class RepeatedTest {

    @Test
    public void test() {
        fail("Not yet implemented");
    }

    public static void main(String args[]) {

        boolean runForever = true;

        while (runForever) {
            Result result = org.junit.runner.JUnitCore.runClasses(RepeatedTest.class);

            if (result.getFailureCount() > 0) {
                runForever = false;
               //Do something with the result object

            }
        }

    }

}
0
silver_mx

По сути, это ответ, который Ишай предоставил выше, переписанный на языке котлин:

@RunWith(Parameterized::class)
class MyTest {

    companion object {

        private const val numberOfTests = 200

        @JvmStatic
        @Parameterized.Parameters
        fun data(): Array<Array<Any?>> = Array(numberOfTests) { arrayOfNulls<Any?>(0) }
    }

    @Test
    fun testSomething() { }
}
0
mark