Ciclo di vita e ordinamento dei test
Controlli l'ordine di esecuzione dei test e gestisca la configurazione e la pulizia usando annotazioni avanzate del ciclo di vita.
Ciclo di vita e ordinamento dei test è una lezione Testing Mastery: JUnit, Mockito & Integration Tests gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Testing Mastery: JUnit, Mockito & Integration Tests, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Testing Mastery: JUnit, Mockito & Integration Tests include 4 lezioni in totale.
Parti di questa lezione non sono ancora state tradotte e vengono mostrate in inglese.
JUnit Test Lifecycle Intro
Welcome! In this lesson, we'll dive into advanced JUnit 5 features to control how your tests run. Understanding the test lifecycle is key to managing resources and ensuring proper test setup and cleanup.
The lifecycle defines the sequence of actions JUnit takes before and after your test methods and classes.
Class-Level Setup: @BeforeAll
Sometimes, you need to perform setup operations only once for all tests within a specific test class. The @BeforeAll annotation marks a method to run before any test method in that class.
By default, @BeforeAll methods must be static. We'll see how to change this soon!
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BeforeAllDemo {
private static StringBuilder log = new StringBuilder();
@BeforeAll
static void setupOnce() {
log.append("-> @BeforeAll: Setup done once.\n");
System.out.println("Setup for all tests.");
}
@Test
void testA() {
log.append(" -> @Test: Running testA.\n");
System.out.println(" Running testA.");
assertTrue(true);
}
@Test
void testB() {
log.append(" -> @Test: Running testB.\n");
System.out.println(" Running testB.");
assertTrue(true);
}
// The log output would typically be verified in @AfterAll or debugger.
}Class-Level Teardown: @AfterAll
Similarly, you might need to clean up resources once after all tests in a class have completed. The @AfterAll annotation marks a method to run after all test methods in the class.
Like @BeforeAll, it must be static by default.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class AfterAllDemo {
private static StringBuilder log = new StringBuilder();
@BeforeAll
static void setup() {
log.append("-> @BeforeAll: Setup for AfterAllDemo.\n");
}
@Test
void testOne() {
log.append(" -> @Test: Running testOne.\n");
assertTrue(true);
}
@Test
void testTwo() {
log.append(" -> @Test: Running testTwo.\n");
assertTrue(true);
}
@AfterAll
static void teardown() {
log.append("-> @AfterAll: Teardown for AfterAllDemo.\n");
System.out.println("--- Execution Log ---");
System.out.println(log.toString()); // See the full order
System.out.println("--- End Log ---");
}
}@TestInstance: PER_CLASS Lifecycle
By default, JUnit creates a new instance of your test class for each test method (Lifecycle.PER_METHOD). This ensures test isolation.
If you need @BeforeAll and @AfterAll methods to be non-static, or if you want to share state across all tests in a class, you can switch the test instance lifecycle to Lifecycle.PER_CLASS.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(Lifecycle.PER_CLASS) // Allows non-static @BeforeAll/@AfterAll
public class PerClassLifecycleDemo {
private int counter = 0; // Instance variable, shared across tests
@BeforeAll // No longer needs to be static!
void setupPerClass() {
counter = 10;
System.out.println("-> @BeforeAll (PER_CLASS). Counter: " + counter);
}
@Test
void testIncrementOne() {
counter++;
System.out.println(" -> @Test 1. Counter: " + counter);
assertEquals(11, counter); // Shared state is modified
}
@Test
void testIncrementTwo() {
counter++;
System.out.println(" -> @Test 2. Counter: " + counter);
assertEquals(12, counter); // Counter continues from previous test
}
@AfterAll // No longer needs to be static!
void teardownPerClass() {
System.out.println("-> @AfterAll (PER_CLASS). Final Counter: " + counter);
}
}Test Ordering: When to Use
Ideally, JUnit tests should be independent and run correctly in any order. Relying on a specific order can make your tests fragile and harder to maintain.
However, there are specific scenarios where explicit ordering might be useful:
- Testing a complex workflow with clear, sequential steps.
- Optimizing performance by grouping fast tests or tests with shared expensive setup.
- Working with legacy systems that demand a certain interaction sequence.
@TestMethodOrder Annotation
To define an execution order for test methods within a class, you use the @TestMethodOrder annotation at the class level. It takes a MethodOrderer implementation as an argument.
JUnit 5 provides several built-in strategies:
Alphanumeric.class: Orders by method name alphabetically.OrderAnnotation.class: Uses the@Orderannotation.Random.class: Randomizes the order.DisplayName.class: Orders by method display names.
Alphanumeric Method Order
Let's see MethodOrderer.Alphanumeric.class in action. JUnit will simply sort test methods based on their names in alphabetical order.
This is a simple way to get a predictable order if your method names naturally follow a sequence.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer.Alphanumeric;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(Alphanumeric.class) // Tests run A, B, C
public class AlphanumericOrderDemo {
@Test
void testA_First() {
System.out.println("-> Running testA_First");
assertTrue(true);
}
@Test
void testC_Third() {
System.out.println("-> Running testC_Third");
assertTrue(true);
}
@Test
void testB_Second() {
System.out.println("-> Running testB_Second");
assertTrue(true);
}
}Custom Order with @Order
For fine-grained control, combine @TestMethodOrder(MethodOrderer.OrderAnnotation.class) with the @Order(value) annotation on individual test methods. Lower value numbers mean earlier execution.
This allows you to define a precise, custom order for your tests.
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(OrderAnnotation.class) // Activate @Order annotation
public class CustomOrderDemo {
@Test
@Order(2) // This test runs second
void processStepTwo() {
System.out.println("-> Running processStepTwo");
assertTrue(true);
}
@Test
@Order(1) // This test runs first
void initializeSystem() {
System.out.println("-> Running initializeSystem");
assertTrue(true);
}
@Test
@Order(3) // This test runs third
void finalizeReport() {
System.out.println("-> Running finalizeReport");
assertTrue(true);
}
}Ordering Best Practices
While powerful, explicit test ordering should be used with caution:
- Prioritize Independence: Each test should ideally be able to run on its own.
- Readability: Over-ordering can make tests harder to understand and maintain.
- Maintenance Burden: Changes to the system might require re-evaluating and updating order values.
Only use ordering when there's a strong, justified reason, and prefer @Order for clear intent.
Lifecycle & Order Check
Consider the following JUnit 5 test class:
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class QuizTest {
private int sharedValue = 0;
@BeforeAll
void setup() {
sharedValue = 10;
System.out.println("BeforeAll: sharedValue = " + sharedValue);
}
@Test
@Order(2)
void testB() {
sharedValue += 2;
System.out.println(" TestB: sharedValue = " + sharedValue);
assertEquals(13, sharedValue);
}
@Test
@Order(1)
void testA() {
sharedValue += 1;
System.out.println(" TestA: sharedValue = " + sharedValue);
assertEquals(11, sharedValue);
}
@AfterAll
void teardown() {
System.out.println("AfterAll: sharedValue = " + sharedValue);
}
}What will be the final value of sharedValue printed in the @AfterAll method?
Recap: Lifecycle & Ordering
In this lesson, you mastered advanced JUnit 5 features for controlling test execution:
- Class-Level Lifecycle:
@BeforeAlland@AfterAllfor one-time setup/teardown. - Instance Lifecycle:
@TestInstance(Lifecycle.PER_CLASS)to enable shared state and non-static class-level hooks. - Test Method Ordering:
@TestMethodOrder(with strategies likeAlphanumericorOrderAnnotation) to define execution order. - Custom Order:
@Orderfor precise control over method sequence.
Remember to use explicit ordering judiciously, prioritizing independent and robust tests!
Domande Frequenti
La lezione «Ciclo di vita e ordinamento dei test» è gratuita?
Sì — il testo completo di «Ciclo di vita e ordinamento dei test» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Testing Mastery: JUnit, Mockito & Integration Tests, passa a CoddyKit PRO. Il corso Testing Mastery: JUnit, Mockito & Integration Tests include 4 lezioni in totale.
Cosa imparerò in «Ciclo di vita e ordinamento dei test»?
Controlli l'ordine di esecuzione dei test e gestisca la configurazione e la pulizia usando annotazioni avanzate del ciclo di vita. Eserciti Testing Mastery: JUnit, Mockito & Integration Tests con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Testing Mastery: JUnit, Mockito & Integration Tests?
Non è richiesta alcuna esperienza precedente. Testing Mastery: JUnit, Mockito & Integration Tests su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Ciclo di vita e ordinamento dei test»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Testing Mastery: JUnit, Mockito & Integration Tests?
Sì. Ogni lezione Testing Mastery: JUnit, Mockito & Integration Tests include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Ciclo di vita e ordinamento dei test
- Test parametrizzati e dinamici
- Test delle eccezioni e timeout
- Test condizionali e assunzioni