Подтвердить что ты не робот

Пометить как не удалось слишком долго. Тесты JUnit

Я хотел бы остановиться и отметить как неудачные слишком длинные тесты junit (выполненные в Maven 3 build). Я знаю три способа сделать это:

1) Использование тестовой аннотации с параметром таймаута:

@Test(timeout=100)
public void testWithTimeout() {
    ...
}

2) Использование аннотации Rule:

@Rule
public Timeout globalTimeout = new Timeout(100);

3) Настройка плагина maven-surefire с помощью следующих параметров:

forkedProcessTimeoutInSeconds=1
reuseForks=false

Ключ 1) и 2) требует изменения каждого теста (он болит, когда у вас много тысяч). 3) решение неприемлемо, так как во многих модулях сначала начинается тест, контекст, который используется результатами тестовых испытаний, резко сократится.

Есть ли у вас какие-либо другие идеи, как достичь этого? Любое сложное решение (не связанное с патчем JUnit:))?

4b9b3361

Ответ 1

Вы можете попытаться определить свой собственный тестовый бегун, написав класс, который расширяет BlockJunit4ClassRunner и завершится неудачно, если выполнение теста превысит определенный тайм-аут. Затем аннотируйте свои тестовые классы с помощью @RunWith (CustomizedTestRunner.class) Вам все равно необходимо изменить классы, но значение таймаута можно указать в одном месте.

Ответ 2

На самом деле правило тайм-аута применяет один и тот же тайм-аут ко всем методам тестирования в классе.

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

Для чего-то, что не требует изменения ко всем классам, вы можете реализовать бегун для пользовательского набора Junit (см. второй пример кода)

Просто для удовольствия, как об этом хакерском решении, используя устаревший метод Thread.stop?

Перед тем, как функция запускает поток наблюдателя для каждого теста, который после таймаута убивает тестовый поток Junit.

Если тест завершен, очистка убивает поток наблюдателя.

Работает для этой маленькой демонстрации, не уверен, что это будет работать на масштабе производства.

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

// You could also make this a base class for test classes
public class TimeoutTest {

    Thread watcherThread ;
    Thread junitTestThread;
    final static int testTimeout = 2000;

    @Before
    public void myInit()
    {
        junitTestThread = Thread.currentThread();
        watcherThread = new Thread()
        {
            @Override 
            public void run()
            {
                    try {
                        Thread.sleep(testTimeout);
                        junitTestThread.stop();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        };
        watcherThread.start();
    }

    @After
    public void myCleanup() throws InterruptedException
    {
        watcherThread.stop();
    }

    @Test
    public void testPassingFastTest() throws InterruptedException {
        Thread.sleep(1000);
    }

    @Test
    public void testFailingSlowTest() throws InterruptedException {
        Thread.sleep(3000);
    }

}

Или сделать это для нескольких тестовых классов, используя набор:

import java.util.Arrays;

import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;

@RunWith(AllTests.class)
public class AllTests extends Suite{

    Thread watcherThread ;
    Thread junitTestThread;
    final static int testTimeout = 70;

    public AllTests(final Class<?> clazz) throws InitializationError {
        super(clazz, findClasses());
      }

    private static Class<?>[] findClasses() {
        // You could write code here to get the list of all test classes from specific directories
        return new  Class<?>[] {TimeoutTest.class,TimeoutTest2.class};
      }


    @Override
    public void run(final RunNotifier notifier) {


      notifier.addListener(new RunListener() {
        @Override
        public void testStarted(final Description description) {            
            System.out.println("Before test " + description.getDisplayName());
            junitTestThread = Thread.currentThread();
            watcherThread = new Thread()
            {
                @Override 
                public void run()
                {
                        try {
                            Thread.sleep(testTimeout);
                            junitTestThread.stop();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                }
            };
            watcherThread.start();

        }

        @Override
        public void testFinished(final Description description) {
            System.out.println("After test " + description.getDisplayName());
            watcherThread.stop();

        }

      }
    );

    super.run(notifier);


    }      
}

Ответ 3

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