Elysia Tools

Explora herramientas, ejemplos, explicaciones visuales y guías temáticas en un solo espacio claro.

Categorías populares

Temas

Idioma
ZHDERUPTENFRES

Elysia Tools

Navegación

Pruebas

Framework de Pruebas JUnit 5

Ejemplos completos de pruebas JUnit 5 incluyendo pruebas unitarias, de integración, parametrizadas, mocking con Mockito y patrones avanzados de prueba para aplicaciones Java

Ejemplos

Entradas de esta colección

CódigojavaSimple

Configuración Básica de JUnit 5

Configuración completa de proyecto JUnit 5 con configuración Maven/Gradle, estructura básica de pruebas y anotaciones comunes

Dificultad

2/10

Tiempo estimado

20 min

Etiquetas

junit5, setup, maven, gradle

Requisitos previos

Java basics, Maven/Gradle, Testing concepts

java
// JUnit 5 Configuration Examples

// 1. Maven Configuration - pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>java-testing-example</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- JUnit 5 version -->
        <junit.version>5.10.1</junit.version>
        <!-- Mockito version -->
        <mockito.version>5.7.0</mockito.version>
        <!-- AssertJ version -->
        <assertj.version>3.24.2</assertj.version>
    </properties>

    <dependencies>
        <!-- JUnit 5 Jupiter -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- JUnit 5 Parameterized Tests -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- JUnit 5 Suite Support -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.10.1</version>
            <scope>test</scope>
        </dependency>

        <!-- Mockito for mocking -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Mockito with JUnit 5 -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- AssertJ for fluent assertions -->
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>${assertj.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Testcontainers for integration testing -->
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>1.19.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- Maven Compiler Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>

            <!-- Maven Surefire Plugin for running tests -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <!-- Include only JUnit 5 tests -->
                    <includes>
                        <include>**/*Test.java</include>
                        <include>**/*Tests.java</include>
                    </includes>

                    <!-- Test configuration -->
                    <systemPropertyVariables>
                        <java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
                    </systemPropertyVariables>

                    <!-- Parallel test execution -->
                    <parallel>methods</parallel>
                    <threadCount>4</threadCount>
                </configuration>
            </plugin>

            <!-- JaCoCo for code coverage -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.11</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>report</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

// 2. Gradle Configuration - build.gradle.kts
plugins {
    java
    jacoco
    application
}

group = "com.example"
version = "1.0.0"

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

dependencies {
    // JUnit 5
    testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
    testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
    testImplementation("org.junit.platform:junit-platform-suite:1.10.1")

    // Mockito
    testImplementation("org.mockito:mockito-core:5.7.0")
    testImplementation("org.mockito:mockito-junit-jupiter:5.7.0")

    // AssertJ
    testImplementation("org.assertj:assertj-core:3.24.2")

    // Testcontainers
    testImplementation("org.testcontainers:junit-jupiter:1.19.3")
}

tasks.test {
    useJUnitPlatform()

    // Configure test execution
    systemProperties("java.util.logging.config.file" to "src/test/resources/logging.properties")

    // Parallel execution
    maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1

    // Test logging
    testLogging {
        events("passed", "skipped", "failed")
        exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
    }
}

// JaCoCo configuration
jacoco {
    toolVersion = "0.8.11"
}

tasks.jacocoTestReport {
    dependsOn(tasks.test)
    reports {
        xml.required.set(true)
        html.required.set(true)
    }
}

// 3. JUnit 5 Configuration - src/test/resources/junit-platform.properties
# JUnit Platform Configuration

# Enable parallel execution
junit.jupiter.execution.parallel.enabled = true

# Parallel execution mode: same_thread, concurrent
junit.jupiter.execution.parallel.mode.default = concurrent

# Class-level parallel mode: same_thread, concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

# Test instance lifecycle: per_class, per_method
junit.jupiter.testinstance.lifecycle.default = per_class

# Display test execution
junit.jupiter.extensions.autodetection.enabled = true

# Condition execution
junit.jupiter.conditions.deactivate = org.junit.*DisabledCondition

# 4. src/test/resources/logback-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>target/test.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

// 5. src/main/java/com/example/calculator/Calculator.java
package com.example.calculator;

public class Calculator {

    public double add(double a, double b) {
        return a + b;
    }

    public double subtract(double a, double b) {
        return a - b;
    }

    public double multiply(double a, double b) {
        return a * b;
    }

    public double divide(double a, double b) {
        if (b == 0) {
            throw new IllegalArgumentException("Cannot divide by zero");
        }
        return a / b;
    }

    public double power(double base, double exponent) {
        return Math.pow(base, exponent);
    }

    public double sqrt(double number) {
        if (number < 0) {
            throw new IllegalArgumentException("Cannot calculate square root of negative number");
        }
        return Math.sqrt(number);
    }
}

// 6. src/test/java/com/example/calculator/CalculatorTest.java
package com.example.calculator;

import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;

class CalculatorTest {

    private Calculator calculator;

    // @BeforeEach - Run before each test
    @BeforeEach
    void setUp() {
        calculator = new Calculator();
        System.out.println("Setting up Calculator instance");
    }

    // @AfterEach - Run after each test
    @AfterEach
    void tearDown() {
        calculator = null;
        System.out.println("Cleaning up Calculator instance");
    }

    // @BeforeAll - Run once before all tests
    @BeforeAll
    static void initAll() {
        System.out.println("Initializing all tests");
    }

    // @AfterAll - Run once after all tests
    @AfterAll
    static void tearDownAll() {
        System.out.println("Cleaning up all tests");
    }

    // Basic test with JUnit 5 assertions
    @Test
    @DisplayName("Should add two numbers correctly")
    @Tag("basic")
    void shouldAddTwoNumbers() {
        // Given
        double a = 5.0;
        double b = 3.0;

        // When
        double result = calculator.add(a, b);

        // Then
        assertEquals(8.0, result, "5 + 3 should equal 8");
        assertThat(result).isEqualTo(8.0);
    }

    @Test
    @DisplayName("Should subtract two numbers correctly")
    @Tag("basic")
    void shouldSubtractTwoNumbers() {
        // Given
        double a = 10.0;
        double b = 4.0;

        // When
        double result = calculator.subtract(a, b);

        // Then
        assertEquals(6.0, result, "10 - 4 should equal 6");
        assertThat(result).isPositive().isGreaterThan(5.0);
    }

    @Test
    @DisplayName("Should multiply two numbers correctly")
    @Tag("basic")
    void shouldMultiplyTwoNumbers() {
        // Given
        double a = 4.0;
        double b = 3.0;

        // When
        double result = calculator.multiply(a, b);

        // Then
        assertEquals(12.0, result, "4 * 3 should equal 12");
        assertThat(result).isEqualTo(12.0);
    }

    @Test
    @DisplayName("Should divide two numbers correctly")
    @Tag("basic")
    void shouldDivideTwoNumbers() {
        // Given
        double a = 15.0;
        double b = 3.0;

        // When
        double result = calculator.divide(a, b);

        // Then
        assertEquals(5.0, result, 0.001, "15 / 3 should equal 5");
        assertThat(result).isBetween(4.9, 5.1);
    }

    @Test
    @DisplayName("Should throw exception when dividing by zero")
    @Tag("exception")
    void shouldThrowExceptionWhenDividingByZero() {
        // Given
        double a = 10.0;
        double b = 0.0;

        // When & Then
        IllegalArgumentException exception = assertThrows(
            IllegalArgumentException.class,
            () -> calculator.divide(a, b),
            "Should throw IllegalArgumentException"
        );

        assertEquals("Cannot divide by zero", exception.getMessage());

        // Alternative with AssertJ
        assertThatThrownBy(() -> calculator.divide(a, b))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessage("Cannot divide by zero");
    }

    // Parameterized test with @ValueSource
    @ParameterizedTest
    @ValueSource(doubles = {0.0, 1.0, 4.0, 9.0, 16.0, 25.0})
    @DisplayName("Should calculate square root correctly")
    @Tag("parameterized")
    void shouldCalculateSquareRootCorrectly(double number) {
        // When
        double result = calculator.sqrt(number);

        // Then
        assertThat(result).isGreaterThanOrEqualTo(0.0);
        assertThat(result * result).isCloseTo(number, within(0.001));
    }

    @ParameterizedTest
    @ValueSource(doubles = {-1.0, -4.0, -9.0})
    @DisplayName("Should throw exception for negative square root")
    @Tag("parameterized")
    void shouldThrowExceptionForNegativeSquareRoot(double number) {
        assertThatThrownBy(() -> calculator.sqrt(number))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessage("Cannot calculate square root of negative number");
    }

    // Parameterized test with @CsvSource
    @ParameterizedTest(name = "Test {index}: {0} ^ {1} = {2}")
    @CsvSource({
        "2.0, 3.0, 8.0",
        "3.0, 2.0, 9.0",
        "5.0, 0.0, 1.0",
        "10.0, 1.0, 10.0"
    })
    @DisplayName("Should calculate power correctly")
    @Tag("parameterized")
    void shouldCalculatePowerCorrectly(double base, double exponent, double expected) {
        // When
        double result = calculator.power(base, exponent);

        // Then
        assertThat(result).isCloseTo(expected, within(0.001));
    }

    // Parameterized test with @MethodSource
    @ParameterizedTest
    @MethodSource("provideMultiplicationData")
    @DisplayName("Should multiply with various inputs")
    @Tag("parameterized")
    void shouldMultiplyWithVariousInputs(double a, double b, double expected) {
        // When
        double result = calculator.multiply(a, b);

        // Then
        assertThat(result).isCloseTo(expected, within(0.001));
    }

    static Stream<Arguments> provideMultiplicationData() {
        return Stream.of(
            Arguments.of(2.5, 4.0, 10.0),
            Arguments.of(-3.0, 2.0, -6.0),
            Arguments.of(0.0, 5.0, 0.0),
            Arguments.of(1.5, 1.5, 2.25)
        );
    }

    // Nested test class
    @Nested
    @DisplayName("Edge Case Tests")
    @Tag("edge-case")
    class EdgeCaseTests {

        @Test
        @DisplayName("Should handle very large numbers")
        void shouldHandleVeryLargeNumbers() {
            // Given
            double largeNumber = Double.MAX_VALUE / 2;

            // When
            double result = calculator.add(largeNumber, 1.0);

            // Then
            assertThat(result).isGreaterThan(largeNumber);
            assertThat(Double.isInfinite(result)).isFalse();
        }

        @Test
        @DisplayName("Should handle floating point precision")
        void shouldHandleFloatingPointPrecision() {
            // Given
            double a = 0.1;
            double b = 0.2;

            // When
            double result = calculator.add(a, b);

            // Then
            assertThat(result).isCloseTo(0.3, within(0.001));
        }
    }

    // Disabled test
    @Test
    @Disabled("This test is disabled for demonstration")
    @DisplayName("Disabled test example")
    void disabledTestExample() {
        fail("This test should not run");
    }

    // Repeated test
    @RepeatedTest(3)
    @DisplayName("Repeated test example")
    void repeatedTestExample(RepetitionInfo repetitionInfo) {
        System.out.println("Running repetition " + repetitionInfo.getCurrentRepetition());
        assertTrue(calculator.add(1, 1) == 2);
    }

    // Test timeout
    @Test
    @Timeout(1) // 1 second timeout
    @DisplayName("Should complete within timeout")
    void shouldCompleteWithinTimeout() throws InterruptedException {
        // This test should complete within 1 second
        Thread.sleep(100);
        assertTrue(calculator.add(1, 1) == 2);
    }

    // Custom assumptions
    @Test
    @DisplayName("Should run only on certain conditions")
    void shouldRunOnlyOnCertainConditions() {
        // Skip test if running on Windows
        Assumptions.assumeFalse(System.getProperty("os.name").toLowerCase().contains("win"),
            "Test skipped on Windows");

        // Continue with test
        assertThat(calculator.add(2, 3)).isEqualTo(5);
    }
}
CódigojavaComplejo

JUnit 5 con Mockito y Testcontainers

Patrones avanzados de prueba usando Mockito para mocking y Testcontainers para pruebas de integración

Dificultad

7/10

Tiempo estimado

45 min

Etiquetas

junit5, mockito, testcontainers, integration

Requisitos previos

Java advanced, Spring Boot, Database concepts, Testing patterns

java
// JUnit 5 Advanced Testing with Mockito and Testcontainers

// 1. src/main/java/com/example/service/UserService.java
package com.example.service;

import com.example.model.User;
import com.example.repository.UserRepository;
import com.example.exception.UserNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class UserService {

    private final UserRepository userRepository;
    private final EmailService emailService;

    public UserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }

    public User createUser(User user) {
        user.setCreatedAt(LocalDateTime.now());
        user.setActive(true);

        User savedUser = userRepository.save(user);

        // Send welcome email
        emailService.sendWelcomeEmail(savedUser.getEmail(), savedUser.getUsername());

        return savedUser;
    }

    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }

    public List<User> getAllActiveUsers() {
        return userRepository.findByActiveTrue();
    }

    public User updateUser(Long id, User userDetails) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));

        user.setUsername(userDetails.getUsername());
        user.setEmail(userDetails.getEmail());
        user.setUpdatedAt(LocalDateTime.now());

        return userRepository.save(user);
    }

    public void deleteUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));

        userRepository.delete(user);
    }

    public User deactivateUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));

        user.setActive(false);
        user.setDeactivatedAt(LocalDateTime.now());

        return userRepository.save(user);
    }
}

// 2. src/main/java/com/example/service/EmailService.java
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class EmailService {

    public void sendWelcomeEmail(String email, String username) {
        // Implementation would send actual email
        System.out.println("Sending welcome email to: " + email);
    }

    public void sendPasswordResetEmail(String email, String resetToken) {
        // Implementation would send password reset email
        System.out.println("Sending password reset email to: " + email);
    }
}

// 3. src/main/java/com/example/model/User.java
package com.example.model;

import jakarta.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String username;

    @Column(unique = true, nullable = false)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private Boolean active = true;

    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    @Column(name = "deactivated_at")
    private LocalDateTime deactivatedAt;

    // Constructors
    public User() {}

    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }

    // Getters and setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }

    public Boolean getActive() { return active; }
    public void setActive(Boolean active) { this.active = active; }

    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }

    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }

    public LocalDateTime getDeactivatedAt() { return deactivatedAt; }
    public void setDeactivatedAt(LocalDateTime deactivatedAt) { this.deactivatedAt = deactivatedAt; }
}

// 4. src/test/java/com/example/service/UserServiceMockitoTest.java
package com.example.service;

import com.example.model.User;
import com.example.repository.UserRepository;
import com.example.exception.UserNotFoundException;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
@DisplayName("UserService Tests with Mockito")
class UserServiceMockitoTest {

    @Mock
    private UserRepository userRepository;

    @Mock
    private EmailService emailService;

    @InjectMocks
    private UserService userService;

    @Captor
    private ArgumentCaptor<User> userCaptor;

    @Test
    @DisplayName("Should create user successfully")
    void shouldCreateUserSuccessfully() {
        // Given
        User userToCreate = new User("testuser", "test@example.com", "password123");
        User savedUser = new User(1L, "testuser", "test@example.com", "password123");
        savedUser.setCreatedAt(LocalDateTime.now());
        savedUser.setActive(true);

        when(userRepository.save(any(User.class))).thenReturn(savedUser);

        // When
        User result = userService.createUser(userToCreate);

        // Then
        assertThat(result).isNotNull();
        assertThat(result.getId()).isEqualTo(1L);
        assertThat(result.getUsername()).isEqualTo("testuser");
        assertThat(result.getEmail()).isEqualTo("test@example.com");
        assertThat(result.getActive()).isTrue();
        assertThat(result.getCreatedAt()).isNotNull();

        // Verify interactions
        verify(userRepository, times(1)).save(userCaptor.capture());
        verify(emailService, times(1)).sendWelcomeEmail("test@example.com", "testuser");

        // Verify captured user
        User capturedUser = userCaptor.getValue();
        assertThat(capturedUser.getUsername()).isEqualTo("testuser");
        assertThat(capturedUser.getActive()).isTrue();
    }

    @Test
    @DisplayName("Should get user by ID when user exists")
    void shouldGetUserByIdWhenUserExists() {
        // Given
        User user = new User(1L, "testuser", "test@example.com", "password123");
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));

        // When
        Optional<User> result = userService.getUserById(1L);

        // Then
        assertThat(result).isPresent();
        assertThat(result.get().getId()).isEqualTo(1L);
        assertThat(result.get().getUsername()).isEqualTo("testuser");

        verify(userRepository, times(1)).findById(1L);
    }

    @Test
    @DisplayName("Should return empty when user does not exist")
    void shouldReturnEmptyWhenUserDoesNotExist() {
        // Given
        when(userRepository.findById(999L)).thenReturn(Optional.empty());

        // When
        Optional<User> result = userService.getUserById(999L);

        // Then
        assertThat(result).isEmpty();
        verify(userRepository, times(1)).findById(999L);
    }

    @Test
    @DisplayName("Should get all active users")
    void shouldGetAllActiveUsers() {
        // Given
        List<User> activeUsers = Arrays.asList(
            new User(1L, "user1", "user1@example.com", "pass1"),
            new User(2L, "user2", "user2@example.com", "pass2")
        );
        when(userRepository.findByActiveTrue()).thenReturn(activeUsers);

        // When
        List<User> result = userService.getAllActiveUsers();

        // Then
        assertThat(result).hasSize(2);
        assertThat(result.get(0).getUsername()).isEqualTo("user1");
        assertThat(result.get(1).getUsername()).isEqualTo("user2");

        verify(userRepository, times(1)).findByActiveTrue();
    }

    @Test
    @DisplayName("Should update user successfully")
    void shouldUpdateUserSuccessfully() {
        // Given
        User existingUser = new User(1L, "olduser", "old@example.com", "password");
        User userDetails = new User("newuser", "new@example.com", "newpassword");

        when(userRepository.findById(1L)).thenReturn(Optional.of(existingUser));
        when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0));

        // When
        User result = userService.updateUser(1L, userDetails);

        // Then
        assertThat(result.getUsername()).isEqualTo("newuser");
        assertThat(result.getEmail()).isEqualTo("new@example.com");
        assertThat(result.getUpdatedAt()).isNotNull();

        verify(userRepository, times(1)).findById(1L);
        verify(userRepository, times(1)).save(any(User.class));
    }

    @Test
    @DisplayName("Should throw exception when updating non-existent user")
    void shouldThrowExceptionWhenUpdatingNonExistentUser() {
        // Given
        User userDetails = new User("newuser", "new@example.com", "newpassword");
        when(userRepository.findById(999L)).thenReturn(Optional.empty());

        // When & Then
        UserNotFoundException exception = assertThrows(
            UserNotFoundException.class,
            () -> userService.updateUser(999L, userDetails)
        );

        assertThat(exception.getMessage()).isEqualTo("User not found with id: 999");
        verify(userRepository, times(1)).findById(999L);
        verify(userRepository, never()).save(any(User.class));
    }

    @Test
    @DisplayName("Should delete user successfully")
    void shouldDeleteUserSuccessfully() {
        // Given
        User user = new User(1L, "testuser", "test@example.com", "password");
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        doNothing().when(userRepository).delete(user);

        // When
        userService.deleteUser(1L);

        // Then
        verify(userRepository, times(1)).findById(1L);
        verify(userRepository, times(1)).delete(user);
    }

    @Test
    @DisplayName("Should deactivate user successfully")
    void shouldDeactivateUserSuccessfully() {
        // Given
        User user = new User(1L, "testuser", "test@example.com", "password");
        user.setActive(true);
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        when(userRepository.save(any(User.class))).thenAnswer(invocation -> invocation.getArgument(0));

        // When
        User result = userService.deactivateUser(1L);

        // Then
        assertThat(result.getActive()).isFalse();
        assertThat(result.getDeactivatedAt()).isNotNull();

        verify(userRepository, times(1)).findById(1L);
        verify(userRepository, times(1)).save(user);
    }

    @Test
    @DisplayName("Should throw exception when deactivating non-existent user")
    void shouldThrowExceptionWhenDeactivatingNonExistentUser() {
        // Given
        when(userRepository.findById(999L)).thenReturn(Optional.empty());

        // When & Then
        UserNotFoundException exception = assertThrows(
            UserNotFoundException.class,
            () -> userService.deactivateUser(999L)
        );

        assertThat(exception.getMessage()).isEqualTo("User not found with id: 999");
        verify(userRepository, times(1)).findById(999L);
        verify(userRepository, never()).save(any(User.class));
    }

    // Test with multiple verifications
    @Test
    @DisplayName("Should create multiple users and verify all interactions")
    void shouldCreateMultipleUsersAndVerifyAllInteractions() {
        // Given
        User user1 = new User("user1", "user1@example.com", "password1");
        User user2 = new User("user2", "user2@example.com", "password2");

        User savedUser1 = new User(1L, "user1", "user1@example.com", "password1");
        User savedUser2 = new User(2L, "user2", "user2@example.com", "password2");

        when(userRepository.save(any(User.class)))
            .thenReturn(savedUser1)
            .thenReturn(savedUser2);

        // When
        userService.createUser(user1);
        userService.createUser(user2);

        // Then
        verify(userRepository, times(2)).save(any(User.class));
        verify(emailService, times(1)).sendWelcomeEmail("user1@example.com", "user1");
        verify(emailService, times(1)).sendWelcomeEmail("user2@example.com", "user2");

        // Verify order of interactions
        InOrder inOrder = inOrder(userRepository, emailService);
        inOrder.verify(userRepository).save(any(User.class));
        inOrder.verify(emailService).sendWelcomeEmail("user1@example.com", "user1");
        inOrder.verify(userRepository).save(any(User.class));
        inOrder.verify(emailService).sendWelcomeEmail("user2@example.com", "user2");
    }
}

// 5. src/test/java/com/example/repository/UserRepositoryIntegrationTest.java
package com.example.repository;

import com.example.model.User;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.*;

@DataJpaTest
@Testcontainers
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("UserRepository Integration Tests")
class UserRepositoryIntegrationTest {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine")
            .withDatabaseName("testdb")
            .withUsername("test")
            .withPassword("test");

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private UserRepository userRepository;

    private User testUser;

    @BeforeEach
    void setUp() {
        testUser = new User("testuser", "test@example.com", "password123");
        testUser.setCreatedAt(LocalDateTime.now());
        testUser.setActive(true);
    }

    @Test
    @Order(1)
    @DisplayName("Should save user successfully")
    void shouldSaveUserSuccessfully() {
        // When
        User savedUser = userRepository.save(testUser);

        // Then
        assertThat(savedUser).isNotNull();
        assertThat(savedUser.getId()).isNotNull();
        assertThat(savedUser.getUsername()).isEqualTo("testuser");
        assertThat(savedUser.getEmail()).isEqualTo("test@example.com");
        assertThat(savedUser.getActive()).isTrue();
    }

    @Test
    @Order(2)
    @DisplayName("Should find user by ID")
    void shouldFindUserById() {
        // Given
        User savedUser = userRepository.save(testUser);

        // When
        Optional<User> foundUser = userRepository.findById(savedUser.getId());

        // Then
        assertThat(foundUser).isPresent();
        assertThat(foundUser.get().getId()).isEqualTo(savedUser.getId());
        assertThat(foundUser.get().getUsername()).isEqualTo("testuser");
    }

    @Test
    @Order(3)
    @DisplayName("Should find user by email")
    void shouldFindUserByEmail() {
        // Given
        userRepository.save(testUser);

        // When
        Optional<User> foundUser = userRepository.findByEmail("test@example.com");

        // Then
        assertThat(foundUser).isPresent();
        assertThat(foundUser.get().getEmail()).isEqualTo("test@example.com");
        assertThat(foundUser.get().getUsername()).isEqualTo("testuser");
    }

    @Test
    @Order(4)
    @DisplayName("Should find user by username")
    void shouldFindUserByUsername() {
        // Given
        userRepository.save(testUser);

        // When
        Optional<User> foundUser = userRepository.findByUsername("testuser");

        // Then
        assertThat(foundUser).isPresent();
        assertThat(foundUser.get().getUsername()).isEqualTo("testuser");
        assertThat(foundUser.get().getEmail()).isEqualTo("test@example.com");
    }

    @Test
    @Order(5)
    @DisplayName("Should find all active users")
    void shouldFindAllActiveUsers() {
        // Given
        User activeUser = new User("activeuser", "active@example.com", "password");
        activeUser.setActive(true);
        activeUser.setCreatedAt(LocalDateTime.now());

        User inactiveUser = new User("inactiveuser", "inactive@example.com", "password");
        inactiveUser.setActive(false);
        inactiveUser.setCreatedAt(LocalDateTime.now());

        userRepository.save(activeUser);
        userRepository.save(inactiveUser);
        userRepository.save(testUser);

        // When
        List<User> activeUsers = userRepository.findByActiveTrue();

        // Then
        assertThat(activeUsers).hasSize(2);
        assertThat(activeUsers.stream().allMatch(User::getActive)).isTrue();
        assertThat(activeUsers).noneMatch(user -> "inactiveuser".equals(user.getUsername()));
    }

    @Test
    @Order(6)
    @DisplayName("Should check if email exists")
    void shouldCheckIfEmailExists() {
        // Given
        userRepository.save(testUser);

        // When & Then
        assertThat(userRepository.existsByEmail("test@example.com")).isTrue();
        assertThat(userRepository.existsByEmail("nonexistent@example.com")).isFalse();
    }

    @Test
    @Order(7)
    @DisplayName("Should check if username exists")
    void shouldCheckIfUsernameExists() {
        // Given
        userRepository.save(testUser);

        // When & Then
        assertThat(userRepository.existsByUsername("testuser")).isTrue();
        assertThat(userRepository.existsByUsername("nonexistent")).isFalse();
    }

    @Test
    @Order(8)
    @DisplayName("Should delete user by ID")
    void shouldDeleteUserById() {
        // Given
        User savedUser = userRepository.save(testUser);
        Long userId = savedUser.getId();

        // When
        userRepository.deleteById(userId);

        // Then
        Optional<User> deletedUser = userRepository.findById(userId);
        assertThat(deletedUser).isEmpty();
    }

    @Test
    @DisplayName("Should handle unique constraint violation")
    void shouldHandleUniqueConstraintViolation() {
        // Given
        userRepository.save(testUser);

        User duplicateUser = new User("differentuser", "test@example.com", "password");

        // When & Then
        assertThatThrownBy(() -> userRepository.saveAndFlush(duplicateUser))
            .hasCauseInstanceOf(org.hibernate.exception.ConstraintViolationException.class);
    }
}

Herramientas

Herramientas que suelen usarse con este ejemplo

Relacionado

Colecciones de ejemplos relacionadas

Relacionado

Temas relacionados

Tema

Corrupción y mutación deliberada de texto para pruebas

Rompa texto limpio con intención — filtre, duplique e invierta frases y palabras, inyecte letras y símbolos aleatorios, desordene líneas y palabras, y demuestre que cada mutación queda bajo control para pruebas de estrés de parsers, ensayos de OCR y experimentos lingüísticos.

Tema

Definición de contratos API, validación de esquemas y pruebas de cambios

Define un contrato API, valida esquemas y cargas capturadas, detecta riesgos de compatibilidad y registra la aceptación.

Tema

Verificación de firmas separadas e integridad de archivos

Calcula o reproduce el hash de un archivo conocido, compáralo con un checksum publicado y verifica una firma Ed25519 separada con una clave pública cuya confianza se confirmó por otra vía.

Tema

Revisión de hojas de contacto y entrega de selección fotográfica

Prepara pruebas numeradas, revisa orientación y privacidad, comprueba imágenes ausentes y recortes en el PDF y entrega un registro que vincule la selección con los originales.

Inicio
Herramientas3212
Banco de trabajo
Ejemplos593
Visualizaciones471
Visores de archivos103
Temas239
Etiquetas333
Imágenes, audio y video657

Herramientas de procesamiento, conversión y optimización de imágenes, audio y video

Matemáticas, fechas y finanzas647

Calculadoras, herramientas numéricas, lógica de fechas, estadística y finanzas

Diseño y color298

Herramientas de color, maquetación, gráficos, estilo visual y apoyo al diseño

Texto y redacción209

Herramientas de redacción, limpieza, formato, extracción y análisis de texto

Desarrollo y Web193

Utilidades para desarrolladores, red, depuración web y automatización

Conversión y codificación175

Herramientas de conversión de formatos, archivos, unidades, archivos comprimidos y codificación

Lanzamiento de un cuestionario de captación y entrega de contactos
Textos conmemorativos: revisión familiar y entrega para impresión
Hábitos privados: copia, restauración y revisión antes de compartir
De artículo a borradores de X y LinkedIn: revisión factual y entrega
Revisión de una lección Markdown interactiva y entrega sin conexión

© 2026 Elysia Tools. Todos los derechos reservados.

DocumentaciónPreciosAcerca deTérminos de servicioPolítica de privacidadCookiesContacto
Pruebas

Framework de Pruebas Jest

Ejemplos completos de pruebas Jest incluyendo pruebas unitarias, de integración, mocking, pruebas asíncronas y patrones avanzados para aplicaciones JavaScript/TypeScript

Pruebas

Framework de Pruebas Pytest

Ejemplos completos de pruebas con Pytest incluyendo pruebas unitarias, de integración, fixtures, parametrización, mocking y patrones avanzados de prueba para aplicaciones Python

Pruebas

Test Pyramid Examples - Guía de Estrategia de Testing

Ejemplos completos de implementación de pirámide de pruebas incluyendo pruebas unitarias, pruebas de integración, pruebas E2E, organización de pruebas y patrones de prueba estratégicos para aseguramiento de calidad de software balanceado

Pruebas

Colecciones Postman - Pruebas API

Ejemplos completos de colecciones Postman incluyendo pruebas de API, scripts de automatización, variables de entorno, servidores mock y patrones avanzados de prueba para REST APIs

Pruebas

BDD with Cucumber - Prácticas de Desarrollo Orientado a Comportamiento

Ejemplos completos de Cucumber BDD incluyendo archivos de características, definiciones de pasos, tablas de datos, hooks y patrones BDD avanzados para desarrollo colaborativo

Pruebas

Framework de Pruebas E2E Cypress

Ejemplos comprensivos de pruebas E2E Cypress incluyendo configuración de pruebas, modelos de objetos de página, pruebas API, pruebas de regresión visual y patrones E2E avanzados para aplicaciones web modernas