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?
JUnit 4: @FixedMethodOrder, Class MethodSorters. Starting JUnit 4.11, we have the annotation @FixMethodOrder and MethodSorters. class supporting the facility of setting an order for a test's execution.
Annotation Type FixMethodOrder. This class allows the user to choose the order of execution of the methods within a test class.
In general, you can't specify the order that separate unit tests run in (though you could specify priorities in TestNG and have a different priority for each test). However, unit tests should be able to be run in isolation, so the order of the tests should not matter.
If you're sure you really want to do this: There may be a better way, but this is all I could come up with...
JUnit4 has an annotation: @RunWith
which lets you override the default Runner for your tests.
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:
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.
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 Article
which is persisted to some kind of persistent storage. If I would like to test the insert, update and delete functionality on the Article
object following the unit test principle "all tests should be reorderable and test only a specific part of the functionality", I would have three tests:
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 Article
object).
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.
That said, I extended Michael D's OrderedRunner
to 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.
This is how it is used. It avoids the need for naming tests like AA_testInsert()
, AB_testUpdate()
, AC_testDelete()
, ..., ZC_testFilter()
, etc.
@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=1
first, order=2
second and last order=3
, no matter if you run them from inside Eclipse, using Ant, or any other way.
Implementation follows. First, the annotation Order
.
@Retention(RetentionPolicy.RUNTIME) public @interface Order { public int order(); }
Then, the modified OrderedRunner
.
public class OrderedRunner extends BlockJUnit4ClassRunner { public OrderedRunner(Class<?> klass) throws InitializationError { super(klass); } @Override protected List<FrameworkMethod> computeTestMethods() { List<FrameworkMethod> copy = new ArrayList<>(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 0; if (o1 == null) return 1; if (o2 == null) return -1; return o1.order() - o2.order(); } }); return list; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With