简体   繁体   English

在 Eclipse 的 JUnit 视图中排序单元测试

[英]Ordering unit tests in Eclipse's JUnit view

The JUnit view in Eclipse seems to order the tests randomly. Eclipse 中的 JUnit 视图似乎对测试进行了随机排序。 How can I order them by class name?如何按班级名称订购它们?

As Gary said in the comments:正如加里在评论中所说:

it would be nice if Unit Runner could be told to go ahead and order them by class name.如果可以告诉 Unit Runner 继续并按类名订购它们,那就太好了。 Hmm, maybe I should look into the source code...嗯,也许我应该查看源代码...

I did look but there's no hint of a functionality to sort these names.我确实看过,但没有提示可以对这些名称进行排序的功能。 I would suggest a change request to the JUnit plugin, but I don't think, that there are lot of people using this thing, so: DIY.我建议对 JUnit 插件提出更改请求,但我不认为有很多人在使用这个东西,所以:DIY。

I would like to see the solution if you modify the plugin code.如果您修改插件代码,我想看看解决方案。

One thing that one might do is using the schema of JUnit 3.x.人们可能会做的一件事是使用 JUnit 3.x 的模式。 We used a test suite that was called AllTests where you add the tests to it in a specific order.我们使用了一个名为 AllTests 的测试套件,您可以在其中按特定顺序向其中添加测试。 And for every package we got another AllTests.对于每个包,我们都有另一个 AllTests。 Giving those test suites a name being the same as the package enables one to easily build a hierarchy that should be valued by the junit plugin.为这些测试套件指定一个与包相同的名称,使人们能够轻松构建应该由 junit 插件重视的层次结构。

I really dislike how it is even presenting the test methods inside the Junit viewer.我真的不喜欢它甚至在 Junit 查看器中展示测试方法的方式。 It should be in the very same order as they are specified in the TestCase class.它应该与它们在 TestCase 类中指定的顺序完全相同。 I order those methods in the way of importance and features.我按照重要性和特征对这些方法进行排序。 So the upmost failing method is to correct first and then the more special one in the later part of the test case.所以最失败的方法是先纠正,然后在测试用例的后面部分纠正更特殊的方法。

That is really annoying that the test runner is scrambling those.测试运行程序正在加扰这些,这真的很烦人。 I will take a look at it myself and if I find a solution I will update this answer.我会自己看看,如果我找到解决方案,我会更新这个答案。

Update:更新:

My problem with the ordering of method names within a TestCase is related to this one: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7023180 (Thanks Oracle!).我在测试用例中的方法名称排序问题与此相关: http ://bugs.sun.com/bugdatabase/view_bug.do?bug_id= 7023180 (感谢 Oracle!)。

So in the end oracle changed the ordering of the methods within a class.getMethods or class.getDeclaredMethods call.所以最后 oracle 改变了 class.getMethods 或 class.getDeclaredMethods 调用中方法的顺序。 Now the methods are random and can change between different runs of the JVM.现在这些方法是随机的,并且可以在 JVM 的不同运行之间改变。 It seams to be related to optimizations of compare or even is an attempt to compress method name - who knows... .它似乎与比较的优化有关,甚至是尝试压缩方法名称 - 谁知道......

So whats left.所以还剩下什么。 First one can use: @FixMethodOrder (from javacodegeeks.com ):第一个可以使用:@FixMethodOrder(来自javacodegeeks.com ):

  1. @FixMethodOrder(MethodSorters.DEFAULT) – deterministic order based on an internal comparator @FixMethodOrder(MethodSorters.DEFAULT) – 基于内部比较器的确定性顺序
  2. @FixMethodOrder(MethodSorters.NAME_ASCENDING) – ascending order of method names @FixMethodOrder(MethodSorters.NAME_ASCENDING) – 方法名称的升序
  3. @FixMethodOrder(MethodSorters.JVM) – pre 4.11 way of depending on reflection based order @FixMethodOrder(MethodSorters.JVM) – 4.11 之前的依赖反射顺序的方式

Well that is stupid but explains why people start using test1TestName schema.嗯,这很愚蠢,但解释了为什么人们开始使用 test1TestName 模式。

Update2 :更新2

I use ASM since Javassist also produces random sorted methods on getMethods().我使用 ASM,因为 Javassist 还在 getMethods() 上生成随机排序的方法。 They use Maps internally.他们在内部使用地图。 With ASM I just use a Visitor.对于 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);
    }
}
}

Just put this in your src/test/java folder in the package org.junit.runners.model.只需将其放在 org.junit.runners.model 包中的 src/test/java 文件夹中。 Now copy the org.junit.runners.model.TestClass of the junit 4.5 lib to the same package and alter its constructor by adding the sorting routine.现在将 junit 4.5 库的 org.junit.runners.model.TestClass 复制到同一个包中,并通过添加排序例程来更改其构造函数。

 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());

}

Here you go.干得好。 Now you have nicely sorted methods in the order they are declared within the java file.现在您已经按照它们在 java 文件中声明的顺序对方法进行了很好的排序。 If you wonder the class path is usually set that way that everything in your src (target or bin) folder is considered first by the classloader.如果您想知道类路径通常是这样设置的,即类加载器首先考虑 src(目标或 bin)文件夹中的所有内容。 So while defining the very same package and the same class you can 'override' every class / interface in any library you use.因此,在定义完全相同的包和相同的类时,您可以“覆盖”您使用的任何库中的每个类/接口。 Thats the trick!这就是诀窍!

Update3 I was able to get a tree view of every package and every class in the right order to. Update3我能够以正确的顺序获得每个包和每个类的树视图。

  • The idea is to subclass ParentRunner and then add all classes to it that you identify as being public and having methods annotated with test.这个想法是对 ParentRunner 进行子类化,然后将所有您标识为公共且具有使用测试注释的方法的类添加到它。
  • Add a getName() method returning only the package name of the class your suite runner is representing (so you see the tree as a package tree without the suite's class name).添加一个 getName() 方法,该方法仅返回您的套件运行器所代表的类的包名称(因此您将树视为没有套件类名称的包树)。
  • Inspect subdirectories if you find a certain suite class (I use AllTests for all suite classes).如果找到某个套件类,请检查子目录(我对所有套件类使用 AllTests)。
  • If you do not find a suite class in a subdirectory check all of its subdirectories, this way you dont miss a package containing tests if the parent directory is not containing a suite.如果您在子目录中没有找到套件类,请检查其所有子目录,这样如果父目录不包含套件,您就不会错过包含测试的包。

That was it.就是这样。 The suite class I add everywhere is: @RunWith(MySuiteRunner.class) public class AllTests { }我随处添加的套件类是: @RunWith(MySuiteRunner.class) public class AllTests { }

That's it.就是这样。 It should you give enough to start and extend on this one.你应该付出足够的努力来开始和扩展这一点。 The suite runner is only using reflection but I sort the test classes and suits of the subdirectories alphabetically and suits of subdirectories (which represent the packages they are in) are sorted upmost.套件运行程序仅使用反射,但我按字母顺序对子目录的测试类和套件进行排序,并且将子目录套件(代表它们所在的包)排在最上面。

Ordering tests in JUnit view has been filed as bug #386453 in Eclipse Bugzilla . JUnit 视图中的排序测试已在 Eclipse Bugzilla 中作为错误 #386453提交。 Commenting and/or voting there may help to get more visibility to this problem.在那里发表评论和/或投票可能有助于更多地了解这个问题。

mark wrote:马克写道:

it orders them base on execution time, maybe you should sort your methods?它根据执行时间对它们进行排序,也许您应该对方法进行排序? source/sort members源/排序成员

mark is right.马克是对的。 But you cannot sort your unit test.但是您无法对单元测试进行排序。 It's not allowed to speculate about the order of execution.不允许猜测执行顺序。

Unit tests have to be built independently and it's random, how they are called by the UnitRunner.单元测试必须独立构建,并且是随机的,UnitRunner 如何调用它们。

In most cases, the test methods are sorted alphabetically.在大多数情况下,测试方法按字母顺序排序。 The classes are random.课程是随机的。 Try to use a TestSuite to order your tests.尝试使用 TestSuite 来订购您的测试。

If you really need hard dependency between your JUnit test, try JExample extension如果您真的需要 JUnit 测试之间的硬依赖,请尝试JExample 扩展

JExample introduces producer-consumer relationships to unit-testing. JExample 将生产者-消费者关系引入到单元测试中。
A producer is a test method that yields its unit under test as return value.生产者是一种测试方法,它产生其被测单元作为返回值。
A consumer is a test method that depends on one or more producers and their return values.消费者是一种依赖于一个或多个生产者及其返回值的测试方法。

You can install it in Eclipse , for Junit4.4 or 4.5.您可以在 Eclipse 中安装它,适用于 Junit4.4 或 4.5。

import jexample.Depends;

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

As mentioned in this IBM article "In pursuit of code quality: JUnit 4 vs. TestNG" :正如这篇 IBM 文章“追求代码质量:JUnit 4 vs. TestNG”中提到的:

One thing the JUnit framework tries to achieve is test isolation . JUnit 框架试图实现的一件事是测试隔离
On the downside, this makes it very difficult to specify an order for test-case execution, which is essential to any kind of dependent testing.不利的一面是,这使得指定测试用例执行的顺序变得非常困难,这对于任何类型的依赖测试都是必不可少的。
Developers have used different techniques to get around this, like specifying test cases in alphabetical order or relying heavily on fixtures ( @Before @After ) to properly set things up.开发人员使用了不同的技术来解决这个问题,比如按字母顺序指定测试用例或严重依赖夹具 ( @Before @After ) 来正确设置。

These workarounds are fine for tests that succeed, but for tests that fail, they have an inconvenient consequence: every subsequent dependent test also fails.这些变通方法适用于成功的测试,但对于失败的测试,它们有一个不方便的后果:每个后续的依赖测试也会失败。 In some situations, this can lead to large test suites reporting unnecessary failures在某些情况下,这可能导致大型测试套件报告不必要的失败

So beware: if you retain any solution for ordering your JUnit tests the way you want... you need to think if that solution support a "skip" feature in order to allow other tests to proceed even if one of them fails.所以请注意:如果您保留任何用于按照您想要的方式订购 JUnit 测试的解决方案……您需要考虑该解决方案是否支持“跳过”功能,以便允许其他测试继续进行,即使其中一个测试失败。

11 years later, the JUnit view does have name ordering, and just got "Execution time" ordering as well. 11 年后,JUnit 视图确实具有名称排序,并且也获得了“执行时间”排序。
See Eclipse 4.17 (2020-09)请参阅Eclipse 4.17 (2020-09)

Sort test results by execution time按执行时间对测试结果进行排序

JUnit view now provides the ability to sort results by execution time. JUnit 视图现在提供按执行时间对结果进行排序的能力。

By default, results will be sorted by execution order.默认情况下,结果将按执行顺序排序。
Choosing Sort By > Execution Time from the JUnit View menu will reorder the results once all tests are complete.一旦所有测试完成,从 JUnit View 菜单中选择Sort By > Execution Time将重新排序结果。

While tests are still running, they will be shown in execution order.当测试仍在运行时,它们将按执行顺序显示。

https://www.eclipse.org/eclipse/news/4.17/images/junit-sort-time-before.png

Sorting by execution order results in:按执行顺序排序的结果是:

https://www.eclipse.org/eclipse/news/4.17/images/junit-sort-time-after.png

I was also searching for a solution for this, and I found a kind of crack from the below URL.我也在为此寻找解决方案,我从下面的 URL 中找到了一种破解方法。 I don't know whether it works for you or not, but it worked for me in Spring Tool Suite 2.5.2.我不知道它是否对你有用,但它在 Spring Tool Suite 2.5.2 中对我有用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM