@Execution annotation in JUnit - Build an Automation Script
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import static org.junit.jupiter.api.Assertions.assertTrue; @Execution(ExecutionMode.CONCURRENT) public class ConcurrentExecutionTest { @Test void testOne() throws InterruptedException { Thread.sleep(2000); assertTrue(true); } @Test void testTwo() throws InterruptedException { Thread.sleep(2000); assertTrue(true); } public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); org.junit.platform.launcher.LauncherDiscoveryRequest request = org.junit.platform.engine.discovery.DiscoverySelectors.selectClass(ConcurrentExecutionTest.class); org.junit.platform.launcher.Launcher launcher = org.junit.platform.launcher.LauncherFactory.create(); launcher.execute( org.junit.platform.launcher.LauncherDiscoveryRequestBuilder.request() .selectors(org.junit.platform.engine.discovery.DiscoverySelectors.selectClass(ConcurrentExecutionTest.class)) .build() ); long end = System.currentTimeMillis(); long duration = end - start; System.out.println("Total execution time (ms): " + duration); assertTrue(duration < 3500, "Tests did not run concurrently as expected"); } }
The test class ConcurrentExecutionTest is annotated with @Execution(ExecutionMode.CONCURRENT) to tell JUnit to run tests in parallel.
Two test methods each sleep for 2 seconds and then assert true to simulate work.
The main method runs the tests programmatically and measures total execution time.
If tests run sequentially, total time would be about 4000 ms (2 tests * 2 seconds each).
If tests run concurrently, total time should be close to 2000 ms.
The assertion checks that total time is less than 3500 ms to confirm concurrency.
Now add three test methods with different sleep durations and verify that total execution time is close to the longest sleep time
Practice
@Execution annotation in JUnit?Solution
Step 1: Understand the role of @Execution
The@Executionannotation controls how tests are run: either all at once (concurrently) or one after another (sequentially).Step 2: Differentiate from other annotations
It does not set order, disable tests, or set timeouts. Those are handled by other annotations like@Order,@Disabled, or@Timeout.Final Answer:
To control whether tests run concurrently or sequentially -> Option DQuick Check:
@Execution controls test concurrency = A [OK]
- Confusing @Execution with @Order
- Thinking it disables tests
- Assuming it sets test timeouts
@Execution in JUnit?Solution
Step 1: Recall valid ExecutionMode values
JUnit definesExecutionMode.CONCURRENTandExecutionMode.SAME_THREAD. There is noSEQUENTIALorPARALLELmode.Step 2: Identify the mode for concurrent execution
ExecutionMode.CONCURRENTruns tests in parallel threads.Final Answer:
@Execution(ExecutionMode.CONCURRENT) -> Option AQuick Check:
Concurrent mode = CONCURRENT [OK]
- Using non-existent ExecutionMode values
- Confusing SAME_THREAD with concurrent
- Misspelling ExecutionMode constants
@Execution(ExecutionMode.CONCURRENT)
class SampleTest {
@Test void testA() { System.out.println("A"); }
@Test void testB() { System.out.println("B"); }
@Test void testC() { System.out.println("C"); }
}Solution
Step 1: Understand ExecutionMode.CONCURRENT effect
With@Execution(ExecutionMode.CONCURRENT), tests run in parallel threads, so their output order is not guaranteed.Step 2: Analyze output behavior
Since threads run independently, print statements may appear in any order depending on thread scheduling.Final Answer:
Tests run concurrently; order of output is unpredictable -> Option BQuick Check:
Concurrent = unpredictable order [OK]
- Assuming concurrent means ordered
- Thinking output is alphabetical
- Confusing concurrent with sequential execution
@Execution:
@Execution(ExecutionMode.CONCURRENT)
class TestExample {
private int counter = 0;
@Test
void increment() {
counter++;
assertEquals(1, counter);
}
@Test
void decrement() {
counter--;
assertEquals(-1, counter);
}
}Solution
Step 1: Analyze shared state usage
Thecountervariable is shared and modified by both tests without synchronization.Step 2: Understand concurrency impact
Running tests concurrently causes race conditions, leading to unpredictable counter values and test failures.Final Answer:
Shared mutable state causes race conditions in concurrent tests -> Option AQuick Check:
Concurrent tests + shared state = race condition [OK]
- Ignoring thread safety in concurrent tests
- Assuming tests run sequentially by default
- Confusing @Execution with @Order annotation
@Execution to optimize test speed while avoiding conflicts?Solution
Step 1: Identify tests with shared data modification
Tests that modify shared data must run sequentially to avoid conflicts.Step 2: Apply @Execution selectively
Use@Execution(ExecutionMode.SAME_THREAD)on tests with shared data, andCONCURRENTon others to speed up execution.Final Answer:
Annotate tests that modify shared data with @Execution(ExecutionMode.SAME_THREAD) and others with CONCURRENT -> Option CQuick Check:
Mix SAME_THREAD for shared data, CONCURRENT for others [OK]
- Running all tests concurrently ignoring shared data
- Running all tests sequentially losing speed benefits
- Not using @Execution selectively per test
Ready to prove it?
Pass the test and this pattern moves unknown
