JUnit Comprehensive Cheatsheet¶
Instalación¶
| Platform | Installation Method |
|---|---|
| Maven (JUnit 5) | Add to INLINE_CODE_8: INLINE_CODE_9 |
| Maven (JUnit 4) | Add to INLINE_CODE_10: INLINE_CODE_11 |
| Gradle (JUnit 5) | Add to INLINE_CODE_12: INLINE_CODE_13 and INLINE_CODE_14 |
| Gradle (JUnit 4) | Add to INLINE_CODE_15: INLINE_CODE_16 |
| Ubuntu/Debian | INLINE_CODE_17 (includes JUnit support) |
| macOS | INLINE_CODE_18 or INLINE_CODE_19 |
| Windows (Chocolatey) | INLINE_CODE_20 or INLINE_CODE_21 |
| Standalone JAR | INLINE_CODE_22 |
Core Annotations (JUnit 5)¶
| Annotation | Description |
|---|---|
| INLINE_CODE_23 | Marks a method as a test method |
| INLINE_CODE_24 | Executes before each test method in the class |
| INLINE_CODE_25 | Executes after each test method in the class |
| INLINE_CODE_26 | Executes once before all tests (must be static) |
| INLINE_CODE_27 | Executes once after all tests (must be static) |
| INLINE_CODE_28 | Provides custom display name for test class or method |
| INLINE_CODE_29 | Disables a test class or method |
| INLINE_CODE_30 | Disables with explanation message |
| INLINE_CODE_31 | Denotes a nested test class for organizing tests |
| INLINE_CODE_32 | Tags tests for filtering (e.g., "slow", "integration") |
| INLINE_CODE_33 | Repeats test execution n times |
| INLINE_CODE_34 | Marks a method as a dynamic test factory |
| INLINE_CODE_35 | Changes test instance lifecycle |
| INLINE_CODE_36 | Fails test if execution exceeds 5 seconds |
| INLINE_CODE_37 | Specifies test execution order when using INLINE_CODE_38 |
Basic Assertions¶
__TABLE_141_
Advanced Assertions¶
__TABLE_142_
Anotaciones de prueba paramétricas¶
__TABLE_143_
Maven Commands¶
__TABLE_144_
Gradle Commands¶
| Command | Description |
|---|---|
| INLINE_CODE_86 | Runs all tests |
| INLINE_CODE_87 | Runs tests using Gradle wrapper |
| INLINE_CODE_88 | Runs specific test class |
| INLINE_CODE_89 | Runs specific test method |
| INLINE_CODE_90 | Runs all classes matching pattern |
| INLINE_CODE_91 | Cleans and runs tests |
| INLINE_CODE_92 | Runs tests continuously on file changes |
| INLINE_CODE_93 | Runs tests with detailed output |
| INLINE_CODE_94 | Runs tests with debug logging |
| INLINE_CODE_95 | Forces test rerun even if up-to-date |
| INLINE_CODE_96 | Stops execution after first test failure |
| INLINE_CODE_97 | Runs tests in parallel |
| INLINE_CODE_98 | Runs tests and generates coverage report |
Configuración¶
Maven Surefire Configuration¶
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<!-- Include/exclude test patterns -->
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
<!-- Parallel execution -->
<parallel>methods</parallel>
<threadCount>4</threadCount>
<!-- Tag filtering -->
<groups>unit, integration</groups>
<excludedGroups>slow</excludedGroups>
<!-- System properties -->
<systemPropertyVariables>
<env>test</env>
</systemPropertyVariables>
</configuration>
</plugin>
Configuración de prueba de grado¶
test {
useJUnitPlatform {
// Include/exclude tags
includeTags 'unit', 'integration'
excludeTags 'slow'
// Include/exclude engines
includeEngines 'junit-jupiter'
excludeEngines 'junit-vintage'
}
// Parallel execution
maxParallelForks = 4
// Test filtering
filter {
includeTestsMatching '*Test'
excludeTestsMatching '*IntegrationTest'
}
// System properties
systemProperty 'env', 'test'
// Test logging
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
showStandardStreams = true
}
// Fail fast
failFast = true
}
JUnit Platform Properties (junit-platform.properties)¶
# Parallel execution
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.config.strategy = fixed
junit.jupiter.execution.parallel.config.fixed.parallelism = 4
# Test instance lifecycle
junit.jupiter.testinstance.lifecycle.default = per_class
# Display name generation
junit.jupiter.displayname.generator.default = org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores
# Automatic extension detection
junit.jupiter.extensions.autodetection.enabled = true
# Deactivate conditions
junit.jupiter.conditions.deactivate = org.junit.*DisabledCondition
Common Use Cases¶
Use Case: Basic Unit Test with Setup and Teardown¶
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class UserServiceTest {
private UserService userService;
private Database mockDb;
@BeforeEach
void setUp() {
mockDb = new MockDatabase();
userService = new UserService(mockDb);
}
@Test
@DisplayName("Should create user with valid data")
void testCreateUser() {
User user = new User("john@example.com", "password123");
User created = userService.createUser(user);
assertNotNull(created.getId());
assertEquals("john@example.com", created.getEmail());
}
@AfterEach
void tearDown() {
mockDb.close();
}
}
Caso de uso: Pruebas parametizadas para múltiples entradas¶
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
class CalculatorTest {
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"10, -5, 5",
"0, 0, 0"
})
void testAddition(int a, int b, int expected) {
Calculator calc = new Calculator();
assertEquals(expected, calc.add(a, b));
}
@ParameterizedTest
@ValueSource(strings = {"", " ", "\t", "\n"})
void testBlankStrings(String input) {
assertTrue(StringUtils.isBlank(input));
}
@ParameterizedTest
@MethodSource("provideEmailTestCases")
void testEmailValidation(String email, boolean expected) {
assertEquals(expected, EmailValidator.isValid(email));
}
static Stream<Arguments> provideEmailTestCases() {
return Stream.of(
Arguments.of("test@example.com", true),
Arguments.of("invalid.email", false),
Arguments.of("@example.com", false)
);
}
}
Use Case: Excepciones Testing and Timeout Verification¶
import org.junit.jupiter.api.Test;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.*;
class PaymentServiceTest {
@Test
void shouldThrowExceptionForInvalidAmount() {
PaymentService service = new PaymentService();
Exception exception = assertThrows(
IllegalArgumentException.class,
() -> service.processPayment(-100)
);
assertEquals("Amount must be positive", exception.getMessage());
}
@Test
void shouldCompleteWithinTimeout() {
PaymentService service = new PaymentService();
assertTimeout(Duration.ofSeconds(2), () -> {
service.processPayment(100);
});
}
@Test
void shouldNotThrowExceptionForValidPayment() {
PaymentService service = new PaymentService();
assertDoesNotThrow(() -> {
service.processPayment(100);
});
}
}
Caso de uso: Tests anidados para la estructura de pruebas organizadas¶
import org.junit.jupiter.api.*;
@DisplayName("Shopping Cart Tests")
class ShoppingCartTest {
@Nested
@DisplayName("When cart is empty")
class EmptyCart {
private ShoppingCart cart;
@BeforeEach
void setUp() {
cart = new ShoppingCart();
}
@Test
@DisplayName("Should have zero items")
void testItemCount() {
assertEquals(0, cart.getItemCount());
}
@Test
@DisplayName("Should have zero total")
void testTotal() {
assertEquals(0.0, cart.getTotal());
}
}
@Nested
@DisplayName("When cart has items")
class CartWithItems {
private ShoppingCart cart;
@BeforeEach
void setUp() {
cart = new ShoppingCart();
cart.addItem(new Item("Book", 29.99));
cart.addItem(new Item("Pen", 2.50));
}
@Test
@DisplayName("Should calculate correct total")
void testTotal() {
assertEquals(32.49, cart.getTotal(), 0.01);
}
@Test
@DisplayName("Should allow item removal")
void testRemoveItem() {
cart.removeItem(0);
assertEquals(1, cart.getItemCount());
}
}
}
Caso de uso: Pruebas de integración con la gestión del ciclo de vida de prueba¶
import org.junit.jupiter.api.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class DatabaseIntegrationTest {
private static DatabaseConnection connection;
private UserRepository userRepository;
@BeforeAll
void setUpDatabase() {
// Expensive one-time setup
connection = DatabaseConnection.connect("jdbc:h2:mem:test");
connection.runMigrations();
}
@BeforeEach
void setUp() {
userRepository = new UserRepository(connection);
connection.beginTransaction();
}
@Test
@Tag("integration")
void testUserPersistence() {
User user = new User("test@example.com");
userRepository.save(user);
User retrieved = userRepository.findById(user.getId());
assertEquals(user.getEmail(), retrieved.getEmail());
}
@AfterEach
void tearDown() {
connection.rollbackTransaction();
}
@AfterAll
void tearDownDatabase() {
connection.close();
}
}
Buenas prácticas¶
- Utilice los nombres de las pruebas descriptivas: Leverage
@DisplayNamepara aclarar los propósitos de las pruebas. Los nombres de los exámenes deben describir lo que se está probando y el resultado esperado (por ejemplo, "debería lanzar la excepción cuando la cantidad es negativa").
Siguiente patrón de AAA: Pruebas de estructura con secciones Arrange (setup), Act (ejecutar), y Assert (verificar) para claridad y mantenimiento.
-
Es una cosa por prueba. Cada método de prueba debe verificar un solo comportamiento o escenario. Esto hace que los fallos sean más fáciles de diagnosticar y las pruebas sean más fáciles de mantener.
-
Use @BeforeEach y @AfterEach sabiamente: Inicia los accesorios de prueba comunes en
@BeforeEachpero evita la configuración excesiva que hace que las pruebas sean difíciles de entender. Limpieza de recursos en@AfterEach_. -
Prefer @Parameterized Prueba para múltiples casos similares: En lugar de escribir varios métodos de prueba similares, utilice pruebas parametrizadas para probar la misma lógica con diferentes entradas.
Use assertAll for related assertions: Afirmaciones relacionadas con el grupo con assertAll() para ver todos los fallos inmediatamente en lugar de parar en el primer fracaso.
-
Pruebas apropiadas: Use
@Tag_ para clasificar las pruebas (unidad, integración, lenta) para que pueda ejecutar selectivamente las suites de prueba en diferentes entornos o etapas CI/CD. -
Evitar las interdependencias de las pruebas* Los exámenes deben ser independientes y ser capaces de funcionar en cualquier orden. Nunca confíes en el orden de ejecución o estado de otras pruebas.
-
Use mensajes de afirmación significativos: Proporcionar mensajes de fallo personalizados a las afirmaciones para facilitar la depuración:
assertEquals(expected, actual, "User email should match"). -
Mantén las pruebas rápido. Las pruebas de unidad deben ejecutarse rápidamente. Mover pruebas lentas (database, red) para separar las suites de prueba de integración utilizando etiquetas o conjuntos de fuentes separados.
Troubleshooting¶
| Issue | Solution |
|---|---|
| Tests not discovered/running | Ensure test methods are INLINE_CODE_105 or package-private, annotated with INLINE_CODE_106, and class names match pattern INLINE_CODE_107 or INLINE_CODE_108. For Maven, verify surefire plugin version ≥ 2.22.0 for JUnit 5 support. |
| NoClassDefFoundError for JUnit classes | Add JUnit dependency with INLINE_CODE_109 in Maven or INLINE_CODE_110 in Gradle. Verify correct JUnit version (5.x for Jupiter, 4.x for legacy). |
| @BeforeAll/@AfterAll must be static error | Methods with INLINE_CODE_111/INLINE_CODE_112 must be INLINE_CODE_113 unless using INLINE_CODE_114 on the test class. |
| Parameterized tests not running | Add INLINE_CODE_115 dependency: INLINE_CODE_116. Ensure method has INLINE_CODE_117 instead of INLINE_CODE_118. |
| Tests pass in IDE but fail in Maven/Gradle | Check for different JUnit versions between IDE and build tool. Verify INLINE_CODE_119 version ≥ 2.22.0 or Gradle has INLINE_CODE_120 in test configuration. |
| Assertion methods not found | Import static assertion methods: INLINE_CODE_121 for JUnit 5 or INLINE_CODE_122 for JUnit 4. |
| Tests run but results not displayed | For Maven, check surefire reports in INLINE_CODE_123. For Gradle, check INLINE_CODE_124 or add INLINE_CODE_125 configuration. |
| Timeout tests failing unexpectedly | Use INLINE_CODE_126 instead of INLINE_CODE_127 if test code doesn't respect interruption. Check for blocking I/O or synchronization issues. |
| Cannot mix JUnit 4 and JUnit 5 annotations | Use JUnit Vintage engine to run JUnit 4 tests alongside JUnit 5, or migrate all tests to JUnit 5. Add INLINE_CODE_128 dependency for backward compatibility. |
Pruebas de curso siempre UP-TO-DATE Utilizar gradle cleanTest test o gradle test --rerun-tasks para forzar la ejecución de pruebas. Compruebe si los archivos fuente de prueba están en el directorio correcto (src/test/java_). Silencio |