JavaRush /Курсы /Модуль 5. Spring /Лекция 265: Практика: тестирование REST API с использован...

Лекция 265: Практика: тестирование REST API с использованием MockMvc

Модуль 5. Spring
27 уровень , 4 лекция
Открыта

Когда мы разрабатываем веб-приложение на Spring — нам нужно проверять, правильно ли оно работает. Для этого существует замечательный инструмент MockMvc. Представьте, что ваше приложение — это современное кафе. В обычной ситуации, чтобы протестировать работу, нужно запустить всё заведение: кухню, зал, посадить официантов. Это как запуск полноценного сервера — долго и сложно. MockMvc — это как если бы вы создали миниатюрную копию кафе с одним поваром и окошком выдачи. Через это окошко можно делать заказы (отправлять запросы) и получать готовые блюда (ответы), не запуская всё заведение целиком. В мире Spring это означает, что мы можем тестировать приложение в облегченном режиме — без полноценного сервера и подключения к базе данных.


Подготовка окружения для тестов

Для начала убедимся, что мы подключили все необходимые зависимости для тестирования. В вашем pom.xml (если вы используете Maven) или build.gradle (если Gradle) должны быть указаны зависимости для Spring Boot Starter Test:

Maven:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Gradle:


testImplementation 'org.springframework.boot:spring-boot-starter-test'

MockMvc уже встроен в Spring Boot Starter Test, так что дополнительных зависимостей не требуется.


Простое тестирование REST API с MockMvc

Входные данные

Допустим, у нас есть REST-контроллер для управления сущностями "Продукт":


@RestController
@RequestMapping("/api/products")
public class ProductController {

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProductById(@PathVariable Long id) {
        // Это упрощённая заглушка. В реальной жизни здесь будет вызов сервиса.
        if (id == 1L) {
            return ResponseEntity.ok(new Product(1L, "Кофе", 5.0));
        }
        return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    }
}

И у нас есть сущность Product:


public class Product {
    private Long id;
    private String name;
    private Double price;

    // Конструкторы, геттеры и сеттеры.
    public Product(Long id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    // Геттеры и сеттеры
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

Пишем тесты

Теперь переходим к написанию тестов для ProductController. Мы хотим убедиться, что:

  1. Если мы запрашиваем ресурс с существующим ID, то получаем корректный результат.
  2. Если ресурс с указанным ID не существует, возвращается статус 404.

public class Product {
    private Long id;
    private String name;
    private Double price;

    // Конструкторы, геттеры и сеттеры.
    public Product(Long id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    // Геттеры и сеттеры
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}
  1. Аннотация @WebMvcTest: указывает, что мы будем тестировать только слой контроллеров. Spring автоматически поднимет минимальное необходимое окружение.
  2. Метод mockMvc.perform(): эмулирует HTTP-запрос. Здесь мы указываем путь (/api/products/1) и метод (GET).
  3. Методы andExpect(): помогают проверить, что приложение возвращает ожидаемый ответ. Мы можем проверять:
    • Статус ответа (isOk(), isNotFound() и другие).
    • Тип контента (contentType()).
    • Содержимое JSON-ответа (jsonPath()).

Тестирование POST-запросов

Теперь добавим в наш контроллер метод для создания продукта:

@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
    product.setId(2L); // Заглушка: всегда возвращаем один и тот же ID
    return ResponseEntity.status(HttpStatus.CREATED).body(product);
}

Напишем тест для этого метода. Мы хотим убедиться, что:

  1. POST-запрос с корректными данными создаёт продукт и возвращает статус 201 (Created).
  2. В теле ответа возвращается созданный продукт.

@Test
public void testCreateProduct() throws Exception {
    String newProductJson = """
        {
            "name": "Чай",
            "price": 3.5
        }
    """;

    mockMvc.perform(post("/api/products") // Эмулируем POST-запрос
            .contentType(MediaType.APPLICATION_JSON) // Указываем, что тело запроса в формате JSON
            .content(newProductJson)) // Передаём JSON-данные
            .andExpect(status().isCreated()) // Ожидаем статус 201 Created
            .andExpect(content().contentType(MediaType.APPLICATION_JSON)) // Ответ тоже JSON
            .andExpect(jsonPath("$.id").value(2)) // Проверяем ID
            .andExpect(jsonPath("$.name").value("Чай")) // Проверяем имя продукта
            .andExpect(jsonPath("$.price").value(3.5)); // Проверяем цену продукта
}

Частые ошибки и особенности

  1. Ошибка "No qualifying bean of type '...' found"
    При использовании @WebMvcTest в тестовом окружении поднимаются только контроллеры. Если в вашем контроллере есть зависимости от сервисов или других компонентов, не забудьте замокировать их с помощью Mockito:
    @MockBean
    private ProductService productService;
    
  2. Некорректное использование @Autowired
    Всегда используйте правильные аннотации (@Autowired или @MockBean) для зависимости.
  3. JSON-формат в запросах
    Убедитесь, что отправляемые JSON-данные в тестах корректны. Используйте contentType(MediaType.APPLICATION_JSON).
  4. Проблемы с jsonPath
    Рекомендуется использовать онлайн-валидаторы JSONPath, чтобы убедиться, что ваш путь указан корректно.

На этом этапе мы научились тестировать REST API с использованием MockMvc. Эти знания помогут вам не только выявлять баги на ранних этапах разработки, но и уверенно проходить собеседования, где вас могут попросить продемонстрировать работу с MockMvc.

Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Артём Уровень 112
3 декабря 2025
Вместо примера с кодом теста ProductController скопирован код сущности Product.