junit5 icon indicating copy to clipboard operation
junit5 copied to clipboard

Impose an order in @BeforeEach methods

Open Cs4r opened this issue 2 years ago • 1 comments

Hi all,

I just wanted to know if there's a possibility we can impose a particular order in execution of methods annotated with @BeforeEach. If so, which interface should I implement or which class should I touch?

For me it would be very useful since I use several beforeEach methods to improve readability of my tests.

Thanks in advance.

Regards.

Cs4r avatar Jul 27 '22 15:07 Cs4r

Hi @Cs4r

From the JUnit 5 documentation of @BeforeEach:

JUnit Jupiter does not guarantee the execution order of multiple @BeforeEach methods that are declared within a single test class or test interface. While it may at times appear that these methods are invoked in alphabetical order, they are in fact sorted using an algorithm that is deterministic but intentionally non-obvious.

Meaning this is intentional.

You probably could just call your setup methods from a single @BeforeEach.

Michael1993 avatar Aug 06 '22 17:08 Michael1993

I have a situation where I need an extension's beforeTestExecution to run before the class's @BeforeEach but it currently doesn't.

Couldn't the @TestMethodOrder be made to also apply to extension points?

This is also a duplicate of #87, but I don't understand the reasoning there. Perhaps that was before @Order was devised?

OrangeDog avatar Feb 23 '23 13:02 OrangeDog

Apparently the problem is that Class.getMethods() is implemented by design to not return the methods in any particular order, so the most intuitive solution (to execute @BeforeEach methods in the order of declaration in the class) is not very easy to implement for the JUnit team.

I think it can still be done by parsing the bytecode with ASM or similar, since the order should be defined there, but it's up to the JUnit team if they want to put effort into this (considering that there are performance issues also, I doubt it).

For now, I'm using the workaround suggested by @Cs4r : have a single @BeforeEach method that calls other methods. I think this solution is actually better than having multiple @BeforeEach methods, since whoever reads the code doesn't need to think in which order are things executed.

cvmocanu avatar Mar 08 '23 18:03 cvmocanu

You probably could just call your setup methods from a single @BeforeEach.

That's definitely the approach I recommend.

Splitting up logic into several "helper methods" is of course fine (and at times recommended), but having each of those methods be a @BeforeEach (or @AfterEach) method is unwise if the invocation order matters.

sbrannen avatar Mar 09 '23 12:03 sbrannen

Apparently the problem is that Class.getMethods() is implemented by design to not return the methods in any particular order, so the most intuitive solution (to execute @BeforeEach methods in the order of declaration in the class) is not very easy to implement for the JUnit team.

I think it can still be done by parsing the bytecode with ASM or similar, since the order should be defined there, but it's up to the JUnit team if they want to put effort into this (considering that there are performance issues also, I doubt it).

That's correct and the primary reason for not ordering them based on source code declaration order.

For now, I'm using the workaround suggested by @Cs4r : have a single @BeforeEach method that calls other methods. I think this solution is actually better than having multiple @BeforeEach methods, since whoever reads the code doesn't need to think in which order are things executed.

I agree with that (as mentioned above).

sbrannen avatar Mar 09 '23 12:03 sbrannen

Hi @OrangeDog,

I have a situation where I need an extension's beforeTestExecution to run before the class's @BeforeEach but it currently doesn't.

That will never work. See the Javadoc for BeforeTestExecutionCallback:

BeforeTestExecutionCallback defines the API for extensions that wish to provide additional behavior to tests immediately before an individual test is executed but after any user-defined setup methods (e.g., @BeforeEach methods) have been executed for that test.

You need to implement BeforeEachCallback to achieve your goal.


This is also a duplicate of #87,

Indeed it is.

but I don't understand the reasoning there. Perhaps that was before @Order was devised?

Yes, that's correct. @Order was introduced in JUnit 5.4; whereas, #87 was closed before 5.0 GA was released.

sbrannen avatar Mar 09 '23 13:03 sbrannen

Team decision: The order of lifecycle methods declared within the same type will remain deterministic but intentionally non-obvious to encourage them to be independent of each other. If you need to set up things in a certain order, you can declare a single lifecycle method that includes all of the logic or delegates to additional helper methods.

marcphilipp avatar May 05 '23 10:05 marcphilipp

not a huge fan cause now i need to pass TestInfo through a few hundres beforeEach calls :/

jonnytest1 avatar Oct 25 '23 14:10 jonnytest1