Тестирование вместе с Spring Boot. Часть 2 | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
PHP Developer. Professional Алгоритмы и структуры данных Разработчик программных роботов (RPA) на базе UiPath и PIX
-27%
Scala-разработчик PHP Developer. Basic C# Developer. Professional
-23%
Архитектура и шаблоны проектирования iOS Developer. Professional MS SQL Server Developer Golang Developer. Professional Vue.js разработчик NoSQL Highload Architect Node.js Developer Web-разработчик на Python Android Developer. Professional Microservice Architecture Reverse-Engineering. Professional React.js Developer Flutter Mobile Developer Разработчик IoT Подготовка к сертификации Oracle Java Programmer (OCAJP) Java Developer. Basic Программист С Супер-интенсив "Tarantool" Специализация Java-разработчик
Инфраструктура
Разработчик программных роботов (RPA) на базе UiPath и PIX
-27%
Administrator Linux. Professional
-26%
Network engineer Разработчик чат-ботов и приложений для виртуальных ассистентов
-15%
Administrator Linux. Advanced Специализация Network engineer
-5%
Cloud Solution Architecture NoSQL Инфраструктурная платформа на основе Kubernetes Базы данных Microservice Architecture Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по использованию и настройке GIT Administrator Linux.Basic Экспресс-курс «IaC Ansible» Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс "Версионирование и командная работа с помощью Git" Network engineer. Basic
Корпоративные курсы
Безопасность веб-приложений Разработчик программных роботов (RPA) на базе UiPath и PIX
-27%
Разработчик чат-ботов и приложений для виртуальных ассистентов
-15%
Agile Project Manager Руководитель поддержки пользователей в IT
-10%
Промышленный ML на больших данных Cloud Solution Architecture NoSQL Node.js Developer Reverse-Engineering. Basic Machine Learning. Professional Супер-практикум по работе с протоколом BGP Game QA Engineer Разработчик IoT Экcпресс-курс «ELK» Enterprise Architect Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» Экспресс-курс «Введение в непрерывную поставку на базе Docker» Вебинар CERTIPORT
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Тестирование вместе с Spring Boot. Часть 2

Spring_Deep_21.11_site-5020-ac4119.png

В прошлой части мы рассмотрели тестирование слоя контроллера, в этой части давайте рассмотрим поближе тестирование бизнес-слоя и слоя JPA-репозиториев.

К примеру у нас есть следующий код:

// ru.otus.example.Main
@EnableJpaRepositories
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class);
    }
}

// ru.otus.example.jpa.PersonRepository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}

// ru.otus.example.service.PersonServiceImpl
public class PersonServiceImpl implements PersonService {
    private final PersonRepository repository;   

    @Autowired
    public PersonServiceImpl(PersonRepository repository) {
        this.repository = repository;
    }

    @Override
    public Person getById(int id) {
        repository.getOne(id);
    }

    // И ещё, конечно, какие-то методы, и их много
}

В данном примере у нас имеется SpringBoot-приложение с JPA-репозиторием и бизнес-сервисом, который работает, в частности, с репозиторием.

Чтобы протестировать сервис (бизнес-слой) в принципе не нужен SpringBoot — всегда можно создать моки (в данном случае PersonRepository), и если класс написан в соответствии с IoC, то нам вполне этого достаточно.

А можем всё-таки использовать аннотацию @SpringBootTest. Зачем, станет понятно чуть позже.

Итак, тест выглядит следующим образом:

@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTests {

    @MockBean
    private PersonRepository personRepository;
    @Autowired
    private PersonService personService


    @Test
    public void testGetById() {
        given(this.personRepository.getById(any()))
            .willReturn(new Person(42, "Ivan"));
        Person person = personService.getById(42);
        assertThat(person.getId()).isEqualTo(42);
        // и какие-нибудь другие проверки
    }
}

Разберёмся немного, как работает аннотация SpringBootTest: 1. Тест c @SpringBootTest находится в пакете ru.otus.example.service. Движок идёт по пакету вверх, пока не встретит класс, помеченный аннотацией @SpringBootConfiguration (как ни странно, это наш Main, потому что аннотация @SpringBootApplication помечена искомой). 2. Далее происходит поиск бинов, сервисов и других конфигураций согласно @ComponentScan (да, эта аннотация тоже включена в @SpringBootApplication), спускаясь от этого класса. 3. Но не все бины будут созданы для теста. Тест содержит поле PersonRepository, помеченное @MockBean. Поэтому вместо реального репозитория, в PersonService придёт мок. 4. Ну и после поднятия контекста в @Autowired придёт созданный сервис.

Подобная аннотация SpringBootTest позволяет также писать интеграционные тесты. В данном примере будет использоваться уже реальный JPA-репозиторий.

@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTests {
    @Autowired
    private PersonService personService


    @Test
    public void testGetByIdFromDb() {
        Person person = personService.getById(42); // уже из базы
        assertThat(person.getId()).isEqualTo(42);
        // и какие-нибудь другие проверки
    }
}

Такие тесты используют настроенную в application.yml базу данных. В принципе, JPA-репозитории можно тестировать на embedded DB без особых проблем. Конечно, использование нативных SQL-скриптов и хранимых процедур сказывается на возможности и смысле такого тестирования. Но если вы используете только чистый JPA и, например, liquibase в формате YAML, то корректность маппингов проверить можно, и даже нужно — это позволит избежать ошибок на реальной БД.

И выглядит тест на JPA вот таким образом:

@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class PersonRepositoryTest {
    @Autowired
    private PersonRepository personRepository;

    // вот такой тест позволит выявить ошибки в маппинге
    // тестировать другие методы в репозитории по большей части не нужно
    @Test
    public void testSaveAndGet() {
        personRepository.getById(new Person(42, "Ivan"));
        Person fromDb = personRepository.getOne(42);
        assertThat(fromDb.getId).isEqualTo(42);
        // и какие-нибудь другие проверки на поля
    }
}
.

На этом всё. Оставим читателю возможность самому изучить, всё-таки, на какой БД это будет выполнено!

Есть вопрос? Пишите комментарий!

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
1 комментарий
0

Добрый день!

При запуске теста вылезаеь такая ошибка Error creating bean with name 'springSecurityFilterChain' defined in class path resource

В самом тесте java.lang.IllegalStateException: Failed to load ApplicationContext

В чем может быть проблема?

Для комментирования необходимо авторизоваться
🔥 Выгодные предложения
Подборка курсов, которые можно приобрести по выгодной цене только до конца июля!