Note: if you have never seen test engines, you might be very confused at the beginning (at least it was for me). There is an example here.
In JUnit5 it is possible to create a custom TestEngine
that can discover and execute tests (not only the standard @Test
-annotated methods). The documentation for this extension is here, but this post is definitely more exhaustive. There are very few resources and demo on this advanced topic, so I tried to experiment a little. For what I have understood, there are basically 2 approaches:
- implementing both
discover
andexecute
methods of theTestEngine
interface - extending from
HierarchicalTestEngine
and implementing only thediscover
method
I would say the second one is the cleanest, even if I am not sure you have the same freedom during the execution phase.
In the first approach setting the TestExecutionResult
for a test container is very easy
public void execute(ExecutionRequest request) {
TestDescriptor rootDescriptor = request.getRootTestDescriptor();
var listener = request.getEngineExecutionListener();
...
listener.executionFinished(containerDescriptor, TestExecutionResult.successful());
}
The entire code is not important in this case, containerDescriptor
is a TestDescriptor
whose getType()
returns Type.CONTAINER
. In the real code I set the TestExecutionResult
based on the results of the tests the container contains.
In the second approach how can I set the test execution result for a container? Afterall, only TestDescriptor
s with getType() == Type.Test
are actually executed, therefore I can easily manipulate the results (overriding the Node.execute
method). I look at the Node
interface to see if there is something useful but I missed it. Even nodeFinished
is not enough since I just receive the TestDescriptor
of the container, not the test execution results of all the children.
Currently, this is the definition of my descriptor:
public class MyTestClassDescriptor extends AbstractTestDescriptor
implements Node<MyEngineExecutionContext> {
public MyTestClassDescriptor(Class<?> testClass, TestDescriptor parent) {
super(...);
...
}
@Override
public Type getType() {
return Type.CONTAINER;
}
}
I can certainly adapt the MyEngineExecutionContext
to store a sort of map with all results, but it seems like reinventing the wheel.
Bonus question: when is the TestExecutionResult
for a container meaningful?