2009-02-04 3 views
35

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

+6

Это приводит меня в орехи в Eclipse, и я хочу, чтобы кто-то добавил это в качестве опции для плагина. Я хочу, чтобы принятый ответ действительно устранил проблему! –

ответ

5

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

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

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

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

+0

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

2

знак писал:

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

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

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

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

+0

Ну, я пытаюсь избежать использования TestSuite. Я ценю независимость от единичных тестов, и я утверждаю, что при их создании, но было бы неплохо, если бы Unit Runner можно было сказать, чтобы идти вперед и заказывать их по имени класса. Хм, может быть, я должен заглянуть в исходный код ... –

2

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

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

Вы можете install it in Eclipse, для Junit4.4 или 4.5.

import jexample.Depends; 

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

Как уже упоминалось в этой статье IBM "In pursuit of code quality: JUnit 4 vs. TestNG":

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

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

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

+1

Думаю, он просто хочет увидеть _results_ в определенном порядке. – guerda

+1

... да, следовательно, мой ответ: поскольку вы не можете сортировать результаты, вы можете попробовать заказать тесты. – VonC

+2

Да, просто результаты. И только потому, что я могу захотеть найти конкретный результат теста после того, как были проведены тесты модулей. Я не уверен, почему Eclipse не может заказать результаты тестирования по мере их запуска. Просто используйте SortedSet. –

0

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

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

3

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

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

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

Update:

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

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

Так что осталось. Во-первых, можно использовать: @FixMethodOrder (от javacodegeeks.com):

  1. @FixMethodOrder (MethodSorters.DEFAULT) - детерминированный порядок, основанный на внутренней компаратора
  2. @FixMethodOrder (MethodSorters.NAME_ASCENDING) - порядке возрастания метода имена
  3. @FixMethodOrder (MethodSorters.JVM) - предварительного 4,11 способом в зависимости от отражения на основе порядка

Хорошо, что это улица upid, но объясняет, почему люди начинают использовать схему test1TestName.

Обновление2:

Я использую 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/тест/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 { }

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

1

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

Смежные вопросы