Книга «Spring Boot 2: лучшие практики для профессионалов»

    imageПривет, Хаброжители! Хотите повысить свою эффективность в разработке корпоративных и облачных Java-приложений?

    Увеличьте скорость и простоту разработки микросервисов и сложных приложений, избавившись от забот по конфигурации Spring.

    Используйте Spring Boot 2 и такие инструменты фреймворка Spring 5, как WebFlux, Security, Actuator, а также фреймворк Micrometer, предоставляющий новый способ сбора метрик.


    Фреймворк тестирования Spring


    Одна из основных идей фреймворка Spring — поощрение создания разработчиками простых и слабо связанных классов, программирование интерфейсов, благодаря чему программное обеспечение становится более надежным и лучше расширяемым. Фреймворк Spring предоставляет инструменты, упрощающие модульное и интеграционное тестирование (на самом деле, если вы действительно программируете интерфейсы, для тестирования функциональности приложений Spring вам не нужен). Другими словами, необходимо, чтобы приложение можно было протестировать с помощью систем тестирования JUnit или TestNG на основе объектов (создаваемых просто с помощью оператора new — без Spring или какого-либо другого контейнера).

    В фреймворк Spring включено несколько пакетов, предназначенных для модульного или интеграционного тестирования приложений. Для модульного тестирования предназначено несколько имитационных объектов (Environment, PropertySource, JNDI, Servlet; реактивные утилиты тестирования ServerHttpRequest и ServerHttpResponse), с помощью которых можно производить изоляционное тестирование кода.

    Одна из чаще всего используемых возможностей тестирования в фреймворке Spring — интеграционное тестирование. Основные его задачи:
    
    • управление кэшированием контейнера Spring IoC в промежутке между выполнениями тестов;
    • управление транзакциями;
    • внедрение зависимостей экземпляров тестовых объектов;
    • создание предназначенных специально для Spring базовых классов.

    Фреймворк Spring обеспечивает легкий способ тестирования посредством интеграции в тесты контекста приложения (ApplicationContext). Модуль тестирования Spring предлагает несколько способов использования ApplicationContext, программным образом и с помощью аннотаций.

    • Аннотация BootstrapWith. Аннотация уровня класса, предназначенная для конфигурации начальной загрузки фреймворка TestContext Spring.
    • Аннотация @ContextConfiguration. Определяет метаданные уровня класса, задающие способ загрузки и настройки ApplicationContext для интеграционных тестов. Это совершенно необходимая для ваших классов аннотация, поскольку именно здесь ApplicationContext загружает все определения компонентов.
    • Аннотация @WebAppConfiguration. Аннотация уровня класса, указывающая, что загружаемым для интеграционного теста контекстом приложения должно быть WebApplicationContext.
    • Аннотация @ActiveProfile. Аннотация уровня класса, указывающая, какой из профилей определения компонентов должен быть активным при загрузке ApplicationContext для интеграционного теста.
    • Аннотация @TestPropertySource. Аннотация уровня класса, предназначенная для задания местоположений файлов свойств и встраиваемых свойств, добавляемых в набор объектов PropertySource в Environment для загружаемого для интеграционного теста ApplicationContext.
    • Аннотация @DirtiesContext. Указывает, что используемый ApplicationContext был «загрязнен» во время выполнения теста (например, модифицирован или поврежден путем изменения состояния компонента-одиночки) и должен быть закрыт.

    Это далеко не все аннотации, существует множество других (@TestExecutionListeners, Commit, Rollback, @BeforeTransaction, @AfterTransaction, Sql, SqlGroup, SqlConfig, Timed, Repeat, @IfProfileValue и т. д.).

    Как вы видите, существует множество вариантов тестирования с помощью фреймворка Spring. Обычно всегда используется аннотация @RunWith, связывающая воедино все элементы фреймворка тестирования. Например:

    @RunWith(SpringRunner.class)
    @ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
    @ActiveProfiles("dev")
    @Transactional
    public class ToDoRepositoryTests {
    
            @Test
            public void ToDoPersistenceTest(){
                    //...
            }
    }

    Теперь взглянем, как следует использовать фреймворк тестирования Spring и какие возможности предоставляет Spring Boot.

    Фреймворк тестирования Spring Boot


    Spring Boot использует мощь фреймворка тестирования Spring, расширяя старые и добавляя новые аннотации и возможности, благодаря которым для разработчиков тестирование значительно упрощается.

    Чтобы начать применять все возможности тестирования Spring Boot, необходимо лишь добавить в приложение зависимость spring-boot-starter-test с указанием области видимости test (scope test). В сервисе Spring Initializr эта зависимость уже добавлена.

    Зависимость spring-boot-starter-test обеспечивает возможность использования нескольких фреймворков тестирования, очень хорошо согласующихся с возможностями тестирования Spring Boot: JUnit, AssertJ, Hamcrest, Mockito, JSONassert и JsonPath. Конечно, существуют и другие фреймворки тестирования, отлично работающие с модулем Spring Boot Test; просто соответствующие зависимости нужно указывать вручную.

    Spring Boot предоставляет аннотацию @SpringBootTest, упрощающую тестирование приложений Spring. Обычно при тестировании приложения Spring необходимо добавить несколько аннотаций для тестирования конкретной возможности или функциональности приложения, но не в Spring Boot — хотя для тестирования все равно нужно указать аннотацию @RunWith(SpringRunner.class); если этого не сделать, любые новые аннотации тестирования Spring Boot будут проигнорированы. У аннотации @SpringBootTest есть полезные для тестирования веб-приложений параметры, например RANDOM_PORT и DEFINED_PORT.

    Следующий фрагмент кода представляет собой каркас теста Spring Boot.

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyTests {
    
            @Test
            public void exampleTest() {
                     ...
            }
    }

    Тестирование конечных точек веб-приложения


    Spring Boot предоставляет удобный способ тестирования конечных точек: имитационную среду под названием класс MockMvc:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class MockMvcToDoTests {
    
            @Autowired
            private MockMvc mvc;
    
            @Test
            public void toDoTest() throws Exception {
                  this.mvc
                  .perform(get("/todo"))
                  .andExpect(status().isOk())
                  .andExpect(content()
                       .contentType(MediaType.APPLICATION_JSON_UTF8));
            }
    }

    Можно также воспользоваться классом TestRestTemplate.

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ToDoSimpleRestTemplateTests {
    
          @Autowired
          private TestRestTemplate restTemplate;
    
          @Test
          public void toDoTest() {
                String body = this.restTemplate.getForObject("/todo", String.class);
                assertThat(body).contains("Read a Book");
          }
    }

    В этом коде показан тест, запускающий полноценный сервер и использующий экземпляр класса TestRestTemplate для обращения к конечной точке /todo. Здесь мы предполагаем, что возвращается объект String (это не лучший способ тестирования возврата JSON; не волнуйтесь, далее мы покажем, как использовать класс TestRestTemplate правильно).

    Имитация компонент


    Модуль тестирования Spring Boot предоставляет аннотацию @MockBean, описывающую имитационный объект Mockito для компонента в ApplicationContext. Другими словами, можно создать имитацию нового компонента Spring или заменить уже существующее определение, добавив эту аннотацию. Помните: все это происходит внутри ApplicationContext.

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class ToDoSimpleMockBeanTests {
    
            @MockBean
            private ToDoRepository repository;
    
            @Test
            public void toDoTest() {
                  given(this.repository.findById("my-id"))
                        .Return(new ToDo("Read a Book"));
                  assertThat(
                        this.repository.findById("my-id").getDescription())
                        .isEqualTo("Read a Book");
            }
    }

    Тестовые срезы Spring Boot


    Одна из важнейших возможностей Spring Boot — выполнение тестов без необходимости в какой-то определенной инфраструктуре. Модуль тестирования Spring Boot включает так называемые срезы (slices), предназначенные для тестирования конкретных частей приложения без использования сервера или СУБД.

    Аннотация @JsonTest


    В модуле тестирования Spring Boot есть аннотация @JsonTest, упрощающая сериализацию/десериализацию JSON-объектов и проверяющая, все ли работает корректно. @JsonTest автоматически настраивает поддерживаемое средство JSON-отображения, в зависимости от найденной по пути к классам библиотеки: Jackson, GSON или JSONB.

    @RunWith(SpringRunner.class)
    @JsonTest
    public class ToDoJsonTests {
    
          @Autowired
          private JacksonTester<ToDo> json;
    
          @Test
          public void toDoSerializeTest() throws Exception {
                ToDo toDo = new ToDo("Read a Book");
    
                assertThat(this.json.write(toDo))
                .isEqualToJson("todo.json");
                assertThat(this.json.write(toDo))
                .hasJsonPathStringValue("@.description");
    
                assertThat(this.json.write(toDo))
                .extractingJsonPathStringValue("@.description")
                .isEqualTo("Read a Book");
          }
    
          @Test
          public void toDoDeserializeTest() throws Exception {
                String content = "{\"description\":\"Read a Book\",\"completed\":
                      true }";
                assertThat(this.json.parse(content))
                      .isEqualTo(new ToDo("Read a Book", true));
                assertThat(
                   this.json.parseObject(content).getDescription())
                .isEqualTo("Read a Book");
          }
    }

    Для тестирования контроллеров без использования полноценного сервера можно воспользоваться предлагаемой Spring Boot аннотацией @WebMvcTest, которая автоматически настраивает инфраструктуру Spring MVC и ограничивает список просматриваемых компонентов следующими: Controller, ControllerAdvice, @JsonComponent, Converter, GenericConverter, Filter, WebMvcConfigurer и HandlerMethodArgumentResolver; благодаря этому вы будете знать, так ли работают ваши контроллеры, как ожидалось.

    Важно понимать, что помеченные как Component компоненты не просматриваются при использовании этой аннотации, но при необходимости можно применить аннотацию @MockBean.

    @RunWith(SpringRunner.class)
    @WebMvcTest(ToDoController.class)
    public class ToDoWebMvcTest {
    
          @Autowired
          private MockMvc mvc;
    
          @MockBean
          private ToDoRepository toDoRepository;
    
          @Test
          public void toDoControllerTest() throws Exception {
                given(this.toDoRepository.findById("my-id"))
                      .Return(new ToDo("Do Homework", true));
                      this.mvc.perform(get("/todo/my-id").accept(MediaType.APPLICATION_
                         JSON_UTF8))
                            .andExpect(status().isOk()).andExpect(content().
                               string("{\"id\":\"my-id\",\"description\":\"Do Homework\",
                               \"completed\":true}"));
          }
    }

    Аннотация @WebFluxTest


    Для реактивных контроллеров Spring Boot предоставляет аннотацию @WebFluxTest. Эта аннотация автоматически настраивает инфраструктуру модуля Spring WebFlux и ищет только Controller, ControllerAdvice, @JsonComponent, Converter, GenericConverter и WebFluxConfigurer.

    Важно понимать, что помеченные как Component компоненты не просматриваются при использовании этой аннотации, но при необходимости вы можете применить аннотацию @MockBean.

    @RunWith(SpringRunner.class)
    @WebFluxTest(ToDoFluxController.class)
    public class ToDoWebFluxTest {
    
          @Autowired
          private WebTestClient webClient;
    
          @MockBean
          private ToDoRepository toDoRepository;
    
          @Test
          public void testExample() throws Exception {
                 given(this.toDoRepository.findAll())
                             .Return(Arrays.asList(new ToDo("Read a Book"), new
                                   ToDo("Buy Milk")));
                 this.webClient.get().uri("/todo-flux").accept(MediaType.
                      APPLICATION_JSON_UTF8)
                           .exchange()
                           .expectStatus().isOk()
                           .expectBody(List.class);
          }
    }

    Аннотация @DataJpaTest


    Для тестирования JPA-приложений модуль тестирования Spring Boot предоставляет аннотацию @DataJpaTest, производящую автоконфигурацию встроенных баз данных, размещаемых в оперативной памяти. Она ищет Entity и не загружает никаких компонентов Component. Кроме того, она предоставляет вспомогательный класс TestEntityManager, ориентированный на тестирование, очень похожий на класс JPA EntityManager.

    @RunWith(SpringRunner.class)
    @DataJpaTest
    public class TodoDataJpaTests {
      
          @Autowired
          private TestEntityManager entityManager;
    
          @Autowired
          private ToDoRepository repository;
    
          @Test
          public void toDoDataTest() throws Exception {
                this.entityManager.persist(new ToDo("Read a Book"));
                Iterable<ToDo> toDos = this.repository.
                       findByDescriptionContains("Read a Book");
                assertThat(toDos.iterator().next()).toString().contains("Read a Book");
          }
    }

    Учтите, что при тестировании с помощью @DataJpaTest используются встроенные СУБД в оперативной памяти. Для тестирования же с настоящей базой данных необходимо снабдить класс теста аннотацией @AutoConfigureTestDatabase(replace=Replace.NONE).

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @AutoConfigureTestDatabase(replace=Replace.NONE)
    public class TodoDataJpaTests {
            //...
    }

    Аннотация @JdbcTest


    Эта аннотация очень похожа на @DataJpaTest; единственное отличие — она выполняет ориентированные исключительно на JDBC тесты. Она производит автоматическую настройку встроенной СУБД, размещаемой в оперативной памяти, и класса JdbcTemplate, пропуская при этом все снабженные аннотацией Component классы.

    @RunWith(SpringRunner.class)
    @JdbcTest
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public class TodoJdbcTests {
    
          @Autowired
          private NamedParameterJdbcTemplate jdbcTemplate;
    
          private CommonRepository<ToDo> repository;
    
            @Test
            public void toDoJdbcTest() {
                  ToDo toDo = new ToDo("Read a Book");
    
                this.repository = new ToDoRepository(jdbcTemplate);
                this.repository.save(toDo);
    
                ToDo result = this.repository.findById(toDo.getId());
                assertThat(result.getId()).isEqualTo(toDo.getId());
            }
    }


    Аннотация @DataMongoTest


    Для тестирования приложений MongoDB модуль тестирования Spring Boot предоставляет аннотацию @DataMongoTest. Она производит автоматическую настройку встроенного размещаемого в оперативной памяти сервера Mongo, если он доступен; если же нет, необходимо добавить нужные свойства spring.data.mongodb.*. Она также производит настройку класса MongoTemplate и ищет аннотации @Document. Компоненты Component пропускаются.

    @RunWith(SpringRunner.class)
    @DataMongoTest
    public class TodoMongoTests {
    
          @Autowired
          private MongoTemplate mongoTemplate;
    
          @Test
          public void toDoMongoTest() {
              ToDo toDo = new ToDo("Read a Book");
              this.mongoTemplate.save(toDo);
    
              ToDo result = this.mongoTemplate.findById(toDo.getId(),ToDo.class);
              assertThat(result.getId()).isEqualTo(toDo.getId());
          }
    }

    При потребности во внешнем сервере MongoDB (невстроенном, размещаемом в оперативной памяти) добавьте в аннотацию @DataMongoTest параметр excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class.

    @RunWith(SpringRunner.class)
    @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
    public class ToDoMongoTests {
            // ...
    }

    Аннотация @RestClientTest


    Еще одна важная аннотация — @RestClientTest, предназначенная для тестирования REST-клиентов. Эта аннотация автоматически производит настройки для поддержки Jackson, GSON и JSONB, а также настраивает класс RestTemplateBuilder и добавляет поддержку MockRestServiceServer.

    @RunWith(SpringRunner.class)
    @RestClientTest(ToDoService.class)
    public class ToDoRestClientTests {
    
          @Autowired
          private ToDoService service;
    
          @Autowired
          private MockRestServiceServer server;
    
          @Test
          public void toDoRestClientTest()
                      throws Exception {
                 String content = "{\"description\":\"Read a Book\",\"completed\":
                       true }";
                this.server.expect(requestTo("/todo/my-id"))
                 .andRespond(withSuccess(content,MediaType.APPLICATION_JSON_UTF8));
                ToDo result = this.service.findById("my-id");
                assertThat(result).isNotNull();
                assertThat(result.getDescription()).contains("Read a Book");
          }
    }

    Существует множество других доступных для использования срезов. Главное, запомнить: для тестирования необязательна полная инфраструктура со всеми запущенными серверами. Упростить тестирование приложений Spring Boot позволяют срезы.

    Об авторе


    Фелипе Гутьеррес (Felipe Gutierrez) — архитектор ПО, получивший дипломы бакалавра и магистра в области вычислительной техники в Институте технологий и высшего образования города Монтеррей, Мексика. У Гутьерреса более 20 лет опыта в сфере IT, он разрабатывал программы для компаний из множества вертикально интегрированных отраслей, таких как государственное управление, розничная торговля, здравоохранение, образование и банковское дело. В настоящее время он работает в компании Pivotal, специализируясь на PAS и PKS для Cloud Foundry, фреймворке Spring, нативных облачных приложениях Spring, Groovy и RabbitMQ, помимо прочих технологий. Он также был архитектором ПО в таких крупных компаниях, как Nokia, Apple, Redbox и Qualcomm. Гутьеррес — автор книг Spring Boot Messaging (Apress, 2017) и Introducing Spring Framework (Apress, 2014).

    О научных редакторах


    Оригинальное издание
    Мануэль Жордан Элера (Manuel Jordan Elera) — разработчик-самоучка и исследователь, обожает изучать новые технологии для своих экспериментов и новых их сочетаний. Мануэль получил премии Springy Award Community Champion и Spring Champion 2013. Немногое имеющееся у него свободное время он посвящает чтению Библии и сочинению музыки на гитаре. Мануэль известен под интернет-псевдонимом dr_pompeii. Он осуществлял научную редактуру многих книг, включая Pro Spring, 4-е издание (Apress, 2014)1, Practical Spring LDAP (Apress, 2013), Pro JPA 2, 2-е издание (Apress, 2013) и Pro Spring Security (Apress, 2013).

    Русскоязычное издание
    Валерий Алексеевич Дмитрущенков работает в IT более 35 лет. Разрабатывал программное обеспечение для множества компаний и отраслей, руководил многими комплексными проектами, включая разработку, внедрение и сопровождение автоматизированных систем. Участвовал в создании крупных проектов для государственных органов, реализованных международными организациями: ООН, USIAD, World Bank в России, Косово, Молдавии и Армении.

    » Более подробно с книгой можно ознакомиться на сайте издательства
    » Оглавление
    » Отрывок

    Для Хаброжителей скидка 25% по купону — Spring Boot

    По факту оплаты бумажной версии книги на e-mail высылается электронная книга.

    Похожие публикации

    Комментарии 1

      +2
      Спасибо за упоминание, мне это льстит :)

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое