Saltar a contenido
_ _

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 @DisplayName para 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 @BeforeEach pero 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