The order is determined by Java classloading and JUnit5's TestEngine [1] (If I'm correct). So there's a difference between JUnit's test execution and Java's class loading.
@BeforeAll vs static block
Remember difference between these two.
static blocks - are executed only once when Java's classloader loads the class in memory e.g. creating a first class instance.
@BeforeAll - methods are executed by JUnit's test engine before all tests in the current test class.
So if you would have another test class extending Base and run all tests, static block will be executed only once, whereas @BeforeAll twice (per each test class).
Explanation of order
- When JUnit executes the tests it instantiate your
Child, which first needs to call a Base.
"A" - Java classloader has not loaded Base class yet, so it loads the class and - calls the static block.
"B" - JUnit's runner sees @BeforeAll annotation and checks wheter it has been called already and if not it calls the method.
"C" - Now Java can finish instatiation of Child so classloader can load it and calls the static block.
"D" - Child is initialized and method annotated by @Test is executed.
Now imagine there's another class e.g. AnotherChild extending Base. We are executing two test classes Child and AnotherChild, so JUnit has to call @BeforeAll twice, but Java already loaded Base class during execution of the first test class, so it will be called only once.
Note, that this is roughly simplified situation and in reality it's a bit complicated (as usual).
[1] https://junit.org/junit5/docs/current/api/org.junit.platform.engine/org/junit/platform/engine/TestEngine.html