Java 在方法级别(而不是类级别)指定 junit 4 测试的顺序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3089151/
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
Specifying an order to junit 4 tests at the Method level (not class level)
提问by K Poole
I know this is bad practice, but it needs to be done, or I'll need to switch to testng. Is there a way, similar to JUnit 3's testSuite, to specify the order of the tests to be run in a class?
我知道这是不好的做法,但需要这样做,否则我需要切换到testng. 有没有类似于 JUnit 3 的 testSuite 的方法来指定要在类中运行的测试的顺序?
采纳答案by Michael D
If you're sure you reallywant to do this: There may be a better way, but this is all I could come up with...
如果你确定你真的想这样做:可能有更好的方法,但这就是我能想到的......
JUnit4 has an annotation: @RunWithwhich lets you override the default Runner for your tests.
JUnit4 有一个注释:@RunWith它允许您覆盖测试的默认 Runner。
In your case you would want to create a special subclass of BlockJunit4ClassRunner, and override computeTestMethods()to return tests in the order you want them executed. For example, let's say I want to execute my tests in reverse alphabetical order:
在您的情况下,您可能希望创建一个特殊的子类BlockJunit4ClassRunner,并覆盖computeTestMethods()以按照您希望它们执行的顺序返回测试。例如,假设我想按逆字母顺序执行我的测试:
public class OrderedRunner extends BlockJUnit4ClassRunner {
public OrderedRunner(Class klass) throws InitializationError {
super(klass);
}
@Override
protected List computeTestMethods() {
List list = super.computeTestMethods();
List copy = new ArrayList(list);
Collections.sort(copy, new Comparator() {
public int compare(FrameworkMethod o1, FrameworkMethod o2) {
return o2.getName().compareTo(o1.getName());
}
});
return copy;
}
}
@RunWith(OrderedRunner.class)
public class OrderOfTest {
@Test public void testA() { System.out.println("A"); }
@Test public void testC() { System.out.println("C"); }
@Test public void testB() { System.out.println("B"); }
}
Running this test produces:
运行此测试会产生:
C B A
For your specific case, you would want a comparator that would sort the tests by name in the order you want them executed. (I would suggest defining the comparator using something like Google Guava's class Ordering.explicit("methodName1","methodName2").onResultOf(...);where onResultOf is provided a function that converts FrameworkMethod to its name... though obviously you are free to implement that any way you want.
对于您的特定情况,您需要一个比较器,可以按照您希望它们执行的顺序按名称对测试进行排序。(我建议使用类似 Google Guava 的类来定义比较器Ordering.explicit("methodName1","methodName2").onResultOf(...);,其中 onResultOf 提供了一个将 FrameworkMethod 转换为其名称的函数......尽管很明显你可以自由地以任何你想要的方式实现它。
回答by joscarsson
I can see several reasons for doing this, especially when using JUnit to run functional tests or test persistent objects. For example, consider an object Articlewhich is persisted to some kind of persistent storage. If I would like to test the insert, update and delete functionality on the Articleobject following the unit test principle "all tests should be reorderable and test only a specific part of the functionality", I would have three tests:
我可以看到这样做的几个原因,尤其是在使用 JUnit 运行功能测试或测试持久对象时。例如,考虑一个Article持久化到某种持久存储的对象。如果我想Article按照单元测试原则“所有测试都应该可重新排序并且只测试功能的特定部分”来测试对象上的插入、更新和删除功能,我将进行三个测试:
testInsertArticle()testUpdateArticle()testDeleteArticle()
testInsertArticle()testUpdateArticle()testDeleteArticle()
However, to be able to test the update functionality, I would first need to insert the article. To test the delete functionality, I would also need to insert an article. So, in practice, the insert functionality is already tested both in testUpdateArticle()and testDeleteArticle(). It is then tempting to just create a test method testArticleFunctionality()which does it all, but methods like that will eventually get huge (and they won't just test part of the functionality of the Articleobject).
但是,为了能够测试更新功能,我首先需要插入文章。为了测试删除功能,我还需要插入一篇文章。因此,在实践中,插入功能已经在testUpdateArticle()和 中进行了测试testDeleteArticle()。然后很容易创建一个测试方法testArticleFunctionality()来完成所有工作,但这样的方法最终会变得庞大(而且它们不会只测试Article对象的部分功能)。
The same goes for running functional tests against for example a restful API. JUnit is great also for these cases if it wasn't for the undeterministic ordering of tests.
对例如 Restful API 运行功能测试也是如此。如果不是因为测试的不确定顺序,JUnit 也适用于这些情况。
That said, I extended Michael D's OrderedRunnerto use annotations to determine order of tests, just thought I should share. It can be extended further, for example by specifying exactly which tests each test depends on, but this is what I'm using for now.
也就是说,我扩展了 Michael DOrderedRunner以使用注释来确定测试顺序,只是想我应该分享。它可以进一步扩展,例如通过准确指定每个测试所依赖的测试,但这就是我现在使用的。
This is how it is used. It avoids the need for naming tests like AA_testInsert(), AB_testUpdate(), AC_testDelete(), ..., ZC_testFilter(), etc.
这就是它的使用方式。它避免了命名测试的需要,如AA_testInsert(), AB_testUpdate(), AC_testDelete(), ... ZC_testFilter(), 等。
@RunWith(OrderedRunner.class)
public class SomethingTest {
@Test
@Order(order=2)
public void testUpdateArticle() {
// test update
}
@Test
@Order(order=1)
public void testInsertArticle() {
// test insert
}
@Test
@Order(order=3)
public void testDeleteArticle() {
// test delete
}
}
No matter how these tests are placed in the file, they will always be run as order=1first, order=2second and last order=3, no matter if you run them from inside Eclipse, using Ant, or any other way.
无论这些测试如何放置在文件中,它们将始终作为order=1first、order=2second 和 lastorder=3运行,无论您是从 Eclipse 内部、使用 Ant 还是任何其他方式运行它们。
Implementation follows. First, the annotation Order.
实施如下。首先,注释Order。
@Retention(RetentionPolicy.RUNTIME)
public @interface Order {
public int order();
}
Then, the modified OrderedRunner.
然后,修改后的OrderedRunner.
public class OrderedRunner extends BlockJUnit4ClassRunner {
public OrderedRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected List<FrameworkMethod> computeTestMethods() {
List<FrameworkMethod> list = super.computeTestMethods();
Collections.sort(list, 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 list;
}
}
回答by kornero
If you want to run junit tests in order "just as they present in your source code", and don't want to modify your tests code, see my note about this here:
如果您想按照“就像它们出现在您的源代码中一样”的顺序运行 junit 测试,并且不想修改您的测试代码,请在此处查看我的注释:
How to run junit tests in order as they present in your source code
But it is really not a good idea, tests must be independent.
但这真的不是一个好主意,测试必须是独立的。
回答by Shiva Kumar
回答by Philippe Blayo
Using junit 4.11the new annotation@FixMethodOrderallows to set a specific order:
使用junit 4.11了新的注释@FixMethodOrder允许设置一个特定的顺序:
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
回答by Trung Pham
Joscarsson and Michael D code in my github repo. I hope they don't mind. I also provide ordered version for Parameterized class. It's already to use as maven dependency
Joscarsson 和 Michael D 代码在我的 github 存储库中。我希望他们不要介意。我还为参数化类提供了订购版本。它已经用作 maven 依赖项
<repositories>
<repository>
<id>git-xxx</id>
<url>https://github.com/crsici/OrderedRunnerJunit4.11/raw/master/</url>
</repository>
</repositories>
<dependency>
<groupId>com.sici.org.junit</groupId>
<artifactId>ordered-runner</artifactId>
<version>0.0.1-RELEASE</version>
</dependency>

