在 Eclipse 的 JUnit 视图中排序单元测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/512778/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ordering unit tests in Eclipse's JUnit view
提问by Gary Kephart
The JUnit view in Eclipse seems to order the tests randomly. How can I order them by class name?
Eclipse 中的 JUnit 视图似乎对测试进行了随机排序。如何按班级名称订购它们?
采纳答案by guerda
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. Hmm, maybe I should look into the source code...
如果可以告诉 Unit Runner 继续并按类名订购它们,那就太好了。嗯,也许我应该查看源代码...
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.
如果您修改插件代码,我想看看解决方案。
回答by Martin Kersten
One thing that one might do is using the schema of JUnit 3.x. We used a test suite that was called AllTests where you add the tests to it in a specific order. And for every package we got another 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 3.x 的模式。我们使用了一个名为 AllTests 的测试套件,您可以在其中按特定顺序向其中添加测试。对于每个包,我们都有另一个 AllTests。为这些测试套件指定一个与包相同的名称使人们能够轻松构建应该由 junit 插件重视的层次结构。
I really dislike how it is even presenting the test methods inside the Junit viewer. It should be in the very same order as they are specified in the TestCase class. 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.
我真的不喜欢它甚至在 Junit 查看器中展示测试方法的方式。它应该与它们在 TestCase 类中指定的顺序完全相同。我按照重要性和特征对这些方法进行排序。所以最失败的方法是先纠正,然后在测试用例的后面部分纠正更特殊的方法。
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. Now the methods are random and can change between different runs of the JVM. It seams to be related to optimizations of compare or even is an attempt to compress method name - who knows... .
所以最后 oracle 改变了 class.getMethods 或 class.getDeclaredMethods 调用中方法的顺序。现在这些方法是随机的,可以在 JVM 的不同运行之间改变。它似乎与比较的优化有关,甚至是尝试压缩方法名称 - 谁知道......
So whats left. First one can use: @FixMethodOrder (from javacodegeeks.com):
所以还剩下什么。第一个可以使用:@FixMethodOrder(来自javacodegeeks.com):
- @FixMethodOrder(MethodSorters.DEFAULT) – deterministic order based on an internal comparator
- @FixMethodOrder(MethodSorters.NAME_ASCENDING) – ascending order of method names
- @FixMethodOrder(MethodSorters.JVM) – pre 4.11 way of depending on reflection based order
- @FixMethodOrder(MethodSorters.DEFAULT) – 基于内部比较器的确定性顺序
- @FixMethodOrder(MethodSorters.NAME_ASCENDING) – 方法名称的升序
- @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(). They use Maps internally. With ASM I just use a Visitor.
我使用 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);
}
}
}
Just put this in your src/test/java folder in the package org.junit.runners.model. 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.
只需将其放在 org.junit.runners.model 包中的 src/test/java 文件夹中。现在将 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. 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. 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!
干得好。现在您已经按照它们在 java 文件中声明的顺序对方法进行了很好的排序。如果您想知道类路径通常是这样设置的,即类加载器首先考虑 src(目标或 bin)文件夹中的所有内容。因此,在定义完全相同的包和相同的类时,您可以“覆盖”您使用的任何库中的每个类/接口。这就是诀窍!
Update3I 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.
- 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).
- Inspect subdirectories if you find a certain suite class (I use AllTests for all suite classes).
- 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.
- 这个想法是对 ParentRunner 进行子类化,然后将所有您标识为公共且具有使用 test 注释的方法的类添加到它。
- 添加一个 getName() 方法,该方法仅返回套件运行器所代表的类的包名称(因此您将树视为没有套件类名称的包树)。
- 如果找到某个套件类,请检查子目录(我对所有套件类使用 AllTests)。
- 如果您在子目录中没有找到套件类,请检查其所有子目录,这样如果父目录不包含套件,您就不会错过包含测试的包。
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.
就是这样。你应该付出足够的努力来开始和扩展这一点。套件运行程序仅使用反射,但我按字母顺序对子目录的测试类和套件进行排序,并且将子目录套件(代表它们所在的包)排在最前面。
回答by mrts
Ordering tests in JUnit view has been filed as bug #386453 in Eclipse Bugzilla. Commenting and/or voting there may help to get more visibility to this problem.
JUnit 视图中的排序测试已在 Eclipse Bugzilla 中作为错误 #386453提交。在那里发表评论和/或投票可能有助于更多地了解这个问题。
回答by guerda
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 来订购您的测试。
回答by VonC
If you really need hard dependency between your JUnit test, try JExample extension
如果您真的需要 JUnit 测试之间的硬依赖,请尝试JExample 扩展
JExample introduces producer-consumer relationships to unit-testing.
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.
JExample 将生产者-消费者关系引入到单元测试中。
生产者是一种测试方法,它产生其被测单元作为返回值。
消费者是一种依赖于一个或多个生产者及其返回值的测试方法。
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.
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.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
JUnit 框架试图实现的一件事是测试隔离。
不利的一面是,这使得指定测试用例执行的顺序变得非常困难,这对于任何类型的依赖测试都是必不可少的。
开发人员使用了不同的技术来解决这个问题,比如按字母顺序指定测试用例或严重依赖夹具 (@Before
@After
) 来正确设置。这些变通方法适用于成功的测试,但对于失败的测试,它们有一个不方便的后果:每个后续的相关测试也会失败。在某些情况下,这可能导致大型测试套件报告不必要的失败
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 测试进行排序的解决方案……您需要考虑该解决方案是否支持“跳过”功能,以便即使其中一个测试失败也允许其他测试继续进行。
回答by Gangadhar Tunugunta
I was also searching for a solution for this, and I found a kind of crack from the below 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 中对我有用。