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

Тестирование блоков заказа в представлении Eclipse JUnit

Представление JUnit в Eclipse, похоже, упорядочивает тесты случайным образом. Как я могу упорядочить их по имени класса?

4b9b3361

Ответ 1

Как сказал Гэри в комментариях:

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

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

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

Ответ 2

Одна вещь, которую можно сделать, - использовать схему JUnit 3.x. Мы использовали тестовый набор, который назывался AllTests, где вы добавляете тесты к нему в определенном порядке. И для каждого пакета мы получили еще один AllTests. Предоставление этим наборам тестов имени совпадает с именем пакета, позволяющим легко построить иерархию, которая должна быть оценена плагином junit.

Мне очень не нравится, как он даже представляет методы тестирования внутри инструмента просмотра Junit. Он должен быть в том же порядке, который указан в классе TestCase. Я заказываю эти методы по важности и особенностям. Таким образом, самый старший метод отказа - сначала исправить, а затем более конкретный в более поздней части тестового примера.

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

Обновление:

Моя проблема с упорядочением имен методов в TestCase связана с этим: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7023180 (Спасибо, Oracle!).

Итак, в конце оракул изменил порядок методов в вызове class.getMethods или class.getDeclaredMethods. Теперь методы являются случайными и могут меняться между разными запусками JVM. Он швы связан с оптимизацией сравнения или даже является попыткой сжать имя метода - кто знает....

Так что осталось. Сначала можно использовать: @FixMethodOrder (от javacodegeeks.com):

  • @FixMethodOrder (MethodSorters.DEFAULT) - детерминированный порядок, основанный на внутреннем компараторе
  • @FixMethodOrder (MethodSorters.NAME_ASCENDING) - возрастающий порядок имен методов
  • @FixMethodOrder (MethodSorters.JVM) - путь до 4.11 в зависимости от порядка на основе отражения.

Ну, это глупо, но объясняет, почему люди начинают использовать схему test1TestName.

Update2

Я использую ASM, так как Javassist также производит случайные отсортированные методы на getMethods(). Они используют Карты внутри страны. С ASM я просто использую посетителя.

package org.junit.runners.model;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import com.flirtbox.ioc.OrderTest;

/**
 * @author Martin Kersten
*/
public class TestClassUtil {
public static class MyClassVisitor extends ClassVisitor {
    private final List<String> names;
    public MyClassVisitor(List<String> names) {
        super(Opcodes.ASM4);
        this.names = names;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
            String signature, String[] exceptions) {
        names.add(name);
        return super.visitMethod(access, name, desc, signature, exceptions);
    }
}

private static List<String> getMethodNamesInCorrectOrder(Class<?> clazz) throws IOException {
    InputStream in = OrderTest.class.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
    ClassReader classReader=new ClassReader(in);
    List<String> methodNames = new ArrayList<>();
    classReader.accept(new MyClassVisitor(methodNames), 0);
    return methodNames;
}

public static void sort(Class<?> fClass, List<FrameworkMethod> list) {
    try {
        final List<String> names = getMethodNamesInCorrectOrder(fClass);
        Collections.sort(list, new Comparator<FrameworkMethod>() {
            @Override
            public int compare(FrameworkMethod methodA, FrameworkMethod methodB) {
                int indexA = names.indexOf(methodA.getName());
                int indexB = names.indexOf(methodB.getName());
                if(indexA == -1)
                    indexA = names.size();
                if(indexB == -1)
                    indexB = names.size();
                return indexA - indexB;
            }
        });
    } catch (IOException e) {
        throw new RuntimeException("Could not optain the method names of " + fClass.getName() + " in correct order", e);
    }
}
}

Просто поместите это в папку src/test/java в пакете org.junit.runners.model. Теперь скопируйте org.junit.runners.model.TestClass из junit 4.5 lib в тот же пакет и измените его конструктор, добавив процедуру сортировки.

 public TestClass(Class<?> klass) {
    fClass= klass;
    if (klass != null && klass.getConstructors().length > 1)
        throw new IllegalArgumentException(
                "Test class can only have one constructor");

    for (Class<?> eachClass : getSuperClasses(fClass))
        for (Method eachMethod : eachClass.getDeclaredMethods())
            addToAnnotationLists(new FrameworkMethod(eachMethod));

            //New Part
    for(List<FrameworkMethod> list : fMethodsForAnnotations.values()) {
        TestClassUtil.sort(fClass, list);
    }

    //Remove once you have verified the class is really picked up
    System.out.println("New TestClass for " + klass.getName());

}

Здесь вы идете. Теперь у вас есть хорошо отсортированные методы в том порядке, в котором они объявлены в java файле. Если вы задаетесь вопросом, путь класса обычно устанавливается таким образом, что все в вашей папке src (target или bin) сначала рассматривается загрузчиком классов. Поэтому, определяя тот же пакет и тот же класс, вы можете "переопределить" каждый класс/интерфейс в любой используемой библиотеке. Это трюк!

Update3 Мне удалось получить древовидный вид каждого пакета и каждого класса в правильном порядке.

  • Идея заключается в подклассе ParentRunner, а затем добавлении к нему всех классов, которые вы определяете как общедоступные, и с помощью методов, аннотированных с тестом.
  • Добавить метод getName(), возвращающий только имя пакета класса, который представляет ваш бегун вашего пакета (так что вы видите дерево как дерево пакета без имени класса пакета).
  • Проверять подкаталоги, если вы найдете определенный класс класса (я использую AllTests для всех классов классов).
  • Если вы не найдете класс класса в подкаталоге, проверьте все его подкаталоги, таким образом вы не пропустите пакет, содержащий тесты, если родительский каталог не содержит пакет.

Вот и все. Класс класса, который я добавляю везде, это: @RunWith(MySuiteRunner.class) public class AllTests { }

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

Ответ 3

mark wrote:

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

Значок

является правильным. Но вы не можете отсортировать свой unit test. Невозможно догадаться о порядке выполнения.

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

В большинстве случаев методы тестирования сортируются по алфавиту. Классы являются случайными. Попробуйте использовать TestSuite для заказа тестов.

Ответ 4

Если вам действительно нужна жесткая зависимость между вашим тестом JUnit, попробуйте расширение JExample

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

Вы можете установить его в Eclipse для Junit4.4 или 4.5.

import jexample.Depends;

  @Test
  @Depends("#testEmpty") 
  public Stack<Integer> testPush(Stack<Integer> $) { 
      $.push(42); 
      assertFalse($.isEmpty()); 
      return $; 
  } 

Как упоминалось в этой статье IBM "В поисках качества кода: JUnit 4 vs. TestNG" :

Одна вещь, которую пытается реализовать инфраструктура JUnit, - это тестовая изоляция.
С другой стороны, это затрудняет определение порядка выполнения тестового сценария, что существенно для любого зависимого тестирования.
Разработчики использовали разные методы, чтобы обойти это, например, указывать тестовые примеры в алфавитном порядке или сильно полагаться на светильники (@Before @After), чтобы правильно настроить вещи.

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

Поэтому будьте осторожны: если вы сохраните какое-либо решение для заказа своих тестов JUnit так, как вы хотите... вам нужно подумать, поддерживает ли это решение функцию "пропустить", чтобы другие тесты могли выполняться, даже если один из них не работает.

Ответ 5

Заказные тесты в представлении JUnit были зарегистрированы как ошибка # 386453 в Eclipse Bugzilla. Комментирование и/или голосование могут помочь повысить видимость этой проблемы.

Ответ 6

Я также искал решение для этого, и я нашел вид трещины из приведенного ниже URL. Я не знаю, работает ли это для вас или нет, но это сработало для меня в Spring Tool Suite 2.5.2.

http://osdir.com/ml/java.junit.user/2002-10/msg00077.html