Как запустить методы тестирования в определенном порядке в JUnit4?

Я хочу выполнить методы тестирования, которые аннотируются @Test в особом порядке.

например:

public class MyTest {
    @Test public void test1(){}
    @Test public void test2(){}
}

Я хочу, чтобы запустить test1() до test2() каждый раз, когда я запустить MyTest, но я не мог найти аннотацию, как @Test(order=xx).

Я думаю, что это довольно важная функция для JUnit, если автор JUnit не хочет функция порядка, почему?

16 ответов


Я думаю, что это довольно важная функция для JUnit, если автор JUnit не хочет функцию заказа, почему?

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

как я использую приспособление теста?

(...) Порядок вызова метода тестирования не гарантируется, так testOneItemCollection () может быть выполнен до testEmptyCollection (). (...)

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

Это, как говорится, если вы действительно хотите пойти в в этом направлении рассмотрите использование TestNG, поскольку он поддерживает запуск методов тестов в любом произвольном порядке изначально (и такие вещи, как указание, что методы зависят от групп методов). Седрик Бьюст объясняет, как это сделать в порядок выполнения тестов в testng.


Если вы избавитесь от существующего экземпляра Junit и загрузите JUnit 4.11 или больше в пути сборки следующий код выполнит методы тестирования в порядке их имен, отсортированных по возрастанию:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {

    @Test
    public void testAcreate() {
        System.out.println("first");
    }
    @Test
    public void testBupdate() {
        System.out.println("second");
    }
    @Test
    public void testCdelete() {
        System.out.println("third");
    }
}

если заказ важен, вы должны сделать заказ самостоятельно.

@Test public void test1() { ... }
@Test public void test2() { test1(); ... }

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

например,

void test1(); 
void test2(); 
void test3(); 


@Test
public void testOrder1() { test1(); test3(); }

@Test(expected = Exception.class)
public void testOrder2() { test2(); test3(); test1(); }

@Test(expected = NullPointerException.class)
public void testOrder3() { test3(); test1(); test2(); }

или, полный тест всех перестановок:

@Test
public void testAllOrders() {
    for (Object[] sample: permute(1, 2, 3)) {
        for (Object index: sample) {
            switch (((Integer) index).intValue()) {
                case 1: test1(); break; 
                case 2: test2(); break; 
                case 3: test3(); break; 
            }
        }
    }
}

здесь permute() - простая функция, которая повторяет все возможные перестановки в коллекцию массива.


миграция в TestNG кажется лучшим способом, но я не вижу здесь четкого решения для jUnit. Вот самое прочитать решение / форматирование Я нашел для jUnit:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {
    @Test
    void stage1_prepareAndTest(){};

    @Test
    void stage2_checkSomething(){};

    @Test
    void stage2_checkSomethingElse(){};

    @Test
    void stage3_thisDependsOnStage2(){};

    @Test
    void callTimeDoesntMatter(){}
}

это гарантирует, что методы stage2 вызываются после stage1 и перед stage3.


Это одна из главных проблем, с которой я столкнулся, когда работал над Junit, и я придумал следующее решение, которое отлично работает для меня:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

public class OrderedRunner extends BlockJUnit4ClassRunner {

    public OrderedRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> list = super.computeTestMethods();
        List<FrameworkMethod> copy = new ArrayList<FrameworkMethod>(list);
        Collections.sort(copy, new Comparator<FrameworkMethod>() {

            @Override
            public int compare(FrameworkMethod f1, FrameworkMethod f2) {
                Order o1 = f1.getAnnotation(Order.class);
                Order o2 = f2.getAnnotation(Order.class);

                if (o1 == null || o2 == null) {
                    return -1;
                }

                return o1.order() - o2.order();
            }
        });
        return copy;
    }
}

также создать интерфейс, как показано ниже:

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

public @interface Order {
public int order();
}

Теперь предположим, что у вас есть класс A, где вы написали несколько тестовых случаев, как показано ниже:

(@runWith=OrderRunner.class)
Class A{
@Test
@Order(order = 1)

void method(){

//do something

}

}

таким образом, выполнение начнется с метода с именем "method()". Спасибо!


изменение (пока не выпущено)https://github.com/junit-team/junit/pull/386 вводит @SortMethodsWith. https://github.com/junit-team/junit/pull/293 по крайней мере, сделал порядок предсказуемым без этого (в Java 7 он может быть довольно случайным).


посмотрите на отчет JUnit. JUnit уже организован пакетом. Каждый пакет имеет (или может иметь) классы TestSuite, каждый из которых, в свою очередь, запускает несколько тестовых наборов. Каждый TestCase может иметь несколько методов тестирования формы public void test*(), каждый из которых фактически станет экземпляром класса TestCase, к которому они принадлежат. Каждый метод тестирования (экземпляр TestCase) имеет имя и критерии pass/fail.

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

в прошлом разработчики тестов в моей позиции организовывали классы TestCase в пакеты, соответствующие части(частям) тестируемого продукта, создавали класс TestCase для каждого теста и делали каждый метод теста отдельным "шагом" в тесте, в комплекте со своими собственными критериями pass/fail в выводе JUnit. Каждый TestCase-это автономный "тест", но отдельные методы или" шаги " теста в пределах TestCase должны выполняться в определенном порядке.

методы TestCase были шагами TestCase, и разработчики тестов получили отдельный критерий pass/fail на шаг теста. Теперь шаги теста перемешаны, и тесты (конечно) терпят неудачу.

например:

Class testStateChanges extends TestCase

public void testCreateObjectPlacesTheObjectInStateA()
public void testTransitionToStateBAndValidateStateB()
public void testTransitionToStateCAndValidateStateC()
public void testTryToDeleteObjectinStateCAndValidateObjectStillExists()
public void testTransitionToStateAAndValidateStateA()
public void testDeleteObjectInStateAAndObjectDoesNotExist()
public void cleanupIfAnythingWentWrong()

каждый метод теста утверждает и сообщает свои собственные отдельные критерии пропуска/отказа. Свернуть это в "один большой метод тестирования " ради упорядочения теряет гранулярность критериев pass/fail каждого "шага" в сводном отчете JUnit. ...и это расстраивает моих менеджеров. В настоящее время они требуют другой альтернативы.

может ли кто-нибудь объяснить, как JUnit с упорядочением метода скремблированного теста будет поддерживать отдельные критерии прохождения/сбоя каждого последовательного шага теста, как показано выше и требуется моим руководством?

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


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

к сожалению, нет времени, чтобы дать полное решение прямо сейчас, но посмотрите на класс:

org.junit.runners.Suite

что позволяет вызывать тестовые случаи (из любого тестового класса) в определенном порядке.

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

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

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


Не уверен, что я согласен, Если я хочу проверить "загрузка файла", а затем проверить "данные, вставленные загрузкой файла", почему бы мне не хотеть, чтобы они были независимы друг от друга? Вполне разумно, я думаю, чтобы иметь возможность запускать их отдельно, а не иметь оба в тестовом примере Голиафа.


см. мое решение здесь: "Junit и java 7."

в этой статье я описываю, как запускать тесты junit по порядку - "так же, как в исходном коде". Тесты будут выполняться, так как ваши методы тестирования отображаются в файле класса.

http://intellijava.blogspot.com/2012/05/junit-and-java-7.html

но, как сказал Паскаль Тивент, это не очень хорошая практика.


Я прочитал несколько ответов и согласен с его не лучшей практикой, но самый простой способ заказать тесты - и способ, которым JUnit запускает тесты по умолчанию, по алфавитному имени по возрастанию.

поэтому просто назовите свои тесты в алфавитном порядке, который вы хотите. Также обратите внимание, что имя теста должно начинаться со словом тест. Просто следите за номерами!--1-->

test12 будет работать до условие_2

Так:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond


пожалуйста, проверьте это:https://github.com/TransparentMarket/junit. Он запускает тест в указанном порядке (определенном в скомпилированном файле класса). Также он имеет alltests suite для запуска тестов, определенных sub package first. Используя реализацию AllTests, можно расширить решение и в фильтрации свойств (мы использовали аннотации @Fast, но они еще не были опубликованы).


вот расширение JUnit, которое может произвести желаемое поведение:https://github.com/aafuks/aaf-junit

Я знаю, что это против авторов философии JUnit, но при использовании JUnit в средах, которые не являются строгим модульным тестированием (как практикуется в Java), это может быть очень полезно.


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

Я знаю, что это не полностью связано с этим вопросом, но, возможно, может помочь в выборе правильной проблемы


вы можете использовать один из этих кусок кода:

@FixMethodOrder(MethodSorters.JVM)OR `@FixMethodOrder(MethodSorters.DEFAULT)` OR `@FixMethodOrder(MethodSorters.NAME_ASCENDING)` before your test class like this:


@FixMethodOrder(MethodSorters.NAME_ASCENDING)


public class BookTest { ...}

JUnit в настоящее время позволяет тестовым методам выполнять порядок с использованием аннотаций классов:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.JVM)
@FixMethodOrder(MethodSorters.DEFAULT)

установить способов заказа вы можете назвать их так:

a_testWorkUnit_WithCertainState_shoulddosomething b_testWorkUnit_WithCertainState_shoulddosomething c_testWorkUnit_WithCertainState_shoulddosomething

вы можете найти вот примеры:.