Spring Boot 2 в действии: пробное тестирование вашего веб-приложения

Spring Boot

1. Обзор

Тестирование программного обеспечения является гарантией качества прикладного программного обеспечения. Разработчики Java, разрабатывающие интерфейсы, часто игнорируют модульное тестирование интерфейса. В качестве Java-разработки, если вы можете смоделировать модульное тестирование, количество ошибок будет значительно уменьшено. Spring предоставляет тестовый модуль, так что сейчас толстый братик возьмет вас поиграть в Mock unit test под springboot.Мы проведем практические операции по unit test контроллера и сервиса.

2. Введение зависимости

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

Введите зависимости, как указано выше, и область действияtest. Эта зависимость предоставляет следующую библиотеку классов

  • JUnit 4: самая мощная среда модульного тестирования Java-приложений.
  • Spring Test & Spring Boot Test: Поддержка тестирования интеграции с Spring Boot.
  • AssertJ: библиотека утверждений Java, обеспечивающая поддержку тестовых утверждений.
  • Hamcrest: Объект совпадает с компонентами утверждения и ограничения.
  • Mockito: Хорошо известный фреймворк для насмешек Java.
  • JSONassert: библиотека утверждений JSON.
  • JsonPath: библиотека манипулирования JSON XPath.

Выше приведены библиотеки классов, которые часто используются в модульном тестировании. Вам лучше провести небольшое исследование, когда у вас будет время.

3. Настройте тестовую среду

Приложение Spring Boot представляет собойSpring ApplicationContext, общий тест не превысит этот диапазон. Тестовая среда обеспечивает@SpringBootTestАннотация для обеспечения поддержки среды модульного тестирования SpringBoot. Версия JUnit, которую вы используете, еслиJUnit 4не забудьте добавить тестовый класс@RunWith(SpringRunner.class),JUnit 5Нет нужды. По умолчанию @SpringBootTest не запускает сервер. вы можете использовать егоwebEnvironmentСвойства дополнительно оптимизируют, как проходят тесты,webEnvironmentСвязанные пояснения:

  • MOCK(по умолчанию): загружает контекст веб-приложения и предоставляет фиктивную веб-среду. Встроенный сервер не будет запущен при этом выборе. Если в пути к классам нет веб-среды, будет создана обычная не-веб-среда.ApplicationContext. вы можете сотрудничать@AutoConfigureMockMvcили@AutoConfigureWebTestClientИмитация веб-приложения.
  • RANDOM_PORT:нагрузкаWebServerApplicationContextИ предоставить истинную веб-среду, включенную в порту случайного веб-контейнера.
  • DEFINED_PORT:нагрузкаWebServerApplicationContextи обеспечить реальную веб-среду иRANDOM_PORTРазница заключается в том, чтобы включить активированный вами порт приложения SpringBoot, который обычно объявляется вapplication.ymlв файле конфигурации.
  • NONE:пройти черезSpringApplicationзагрузить одинApplicationContext. Но не предоставляет никакой веб-среды (будь то Mock или что-то другое).

Примечание. Если ваш тест с@TransactionalПри аннотации транзакция откатывается после выполнения каждого тестового метода по умолчанию. но когда твойwebEnvironmentУстановить какRANDOM_PORTилиDEFINED_PORT, то есть, когда реальная веб-среда сервлета предоставляется неявно, она не будет откатываться. Это особенно важно, чтобы гарантировать, что грязные данные не будут записаны в тестах выпуска продукции.

4. Напишите тестовые классы для проверки вашего API

Ближе к дому, сначала мы написалиBookServiceКак сервисный уровень ​

package cn.felord.mockspringboot.service;

import cn.felord.mockspringboot.entity.Book;

/**
 * The interface Book service.
 *
 * @author Dax
 * @since 14 :54  2019-07-23
 */
public interface BookService {

    /**
     * Query by title book.
     *
     * @param title the title
     * @return the book
     */
    Book queryByTitle(String title);

}

Класс реализации выглядит следующим образом.Для простоты и ясности слой сохранения не тестируется.Если уровень сохранения необходимо протестировать, обратите внимание на добавление, удаление и изменение аннотаций транзакций Spring.@TransactionalПоддерживается с целью отката после тестирования.

package cn.felord.mockspringboot.service.impl;

import cn.felord.mockspringboot.entity.Book;
import cn.felord.mockspringboot.service.BookService;
import org.springframework.stereotype.Service;

import java.time.LocalDate;

/**
 * @author Dax
 * @since 14:55  2019-07-23
 */
@Service
public class BookServiceImpl implements BookService {


    @Override
    public Book queryByTitle(String title) {
        Book book = new Book();
        book.setAuthor("dax");
        book.setPrice(78.56);
        book.setReleaseTime(LocalDate.of(2018, 3, 22));
        book.setTitle(title);
        return book;
    }
}

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

package cn.felord.mockspringboot.api;

import cn.felord.mockspringboot.entity.Book;
import cn.felord.mockspringboot.service.BookService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author Dax
 * @since 10:24  2019-07-23
 */
@RestController
@RequestMapping("/book")
public class BookApi {
    @Resource
    private BookService bookService;

    @GetMapping("/get")
    public Book getBook(String title) {
        return bookService.queryByTitle(title);
    }

}

Мы в проекте Spring Boot mavenмодульный тестовый пакет testНапишите свой собственный тестовый класс под соответствующим путем к классам

 package cn.felord.mockspringboot;
 
 import cn.felord.mockspringboot.entity.Book;
 import cn.felord.mockspringboot.service.BookService;
 import org.assertj.core.api.Assertions;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.BDDMockito;
 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
 import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
 import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
 
 import javax.annotation.Resource;
 import java.time.LocalDate;
 
 /**
  * The type Mock springboot application tests.
  */
 @RunWith(SpringRunner.class)
 @SpringBootTest
 @AutoConfigureMockMvc
 public class MockSpringbootApplicationTests {
     @Resource
     private MockMvc mockMvc;
     @MockBean
     private BookService bookService;
 
     @Test
     public void bookApiTest() throws Exception {
         String title = "java learning";
         // mockbean 开始模拟
         bookServiceMockBean(title);
         // mockbean 模拟完成
         String expect = "{\"title\":\"java learning\",\"author\":\"dax\",\"price\":78.56,\"releaseTime\":\"2018-03-22\"}";
         mockMvc.perform(MockMvcRequestBuilders.get("/book/get")
                 .param("title", title))
                 .andExpect(MockMvcResultMatchers.content()
                         .json(expect))
                 .andDo(MockMvcResultHandlers.print());
         // mockbean 重置
     }
   
     @Test
     public void bookServiceTest() {
 
         String title = "java learning";
         bookServiceMockBean(title);
 
 
         Assertions.assertThat(bookService.queryByTitle("ss").getTitle()).isEqualTo(title);
 
     }
       /**
        * Mock打桩
        * @param title the title
        */   
     private void bookServiceMockBean(String title) {
 
         Book book = new Book();
         book.setAuthor("dax");
         book.setPrice(78.56);
         book.setReleaseTime(LocalDate.of(2018, 3, 22));
         book.setTitle(title);
 
         BDDMockito.given(bookService.queryByTitle(title)).willReturn(book);
     }
  }

Излишне говорить, что первые две аннотации тестового класса, третья аннотация@AutoConfigureMockMvcВозможно, вы незнакомы. Это используется для запуска автоматической настройки тестов Mock MVC.

Затем мы пишем тестовый методbookApiTest()тестироватьBookApi#getBook(String title)интерфейс. ​

логикаMockMvcСделайте фиктивный запрос на получение и ожидайте, что результат будетexpectJson и распечатайте соответствующий объект (указан на рис. 1 ниже). Выдает, если запрос не выполненjava.lang.AssertionErrorошибка, поместит ожидаемое значение (Expected) и фактическое значение (отмечено на рис. 2 ниже). Если это так же, как ожидалось, появится только следующая цифра 1.

5. Пробная забивка

Существует очень распространенная ситуация, могут быть другие услуги в разработке вашего звонка, не завершают разработку, например, вы должны отправить интерфейс текстового сообщения, чтобы все еще пройти через форматы SMS-интерфейсы, но вам также нужно Тестовый короткий интерфейс сообщения. ты можешь пройти@MockBeanСоздайте реализацию абстрактного интерфейса. ЛентаBookServiceНапример, если логика его класса реализации не определена, мы можем смоделировать логику bean-компонента, указав его входные параметры и соответствующие возвращаемые значения, или выбрать операцию маршрутизации в соответствии с определенной ситуацией (если входным параметром является A, то результат B, если C, то D). Эта симуляция также известна как тестовая заглушка. Здесь мы будем использоватьMockito

Сценарий тестирования описывается следующим образом:

  1. Определяет возвращаемое значение объекта укладки
  2. Определение количества способов вызова и вызов метода объекта укладки
  3. Укладка указанного объекта Выдает конкретное исключение

Как правило, следующие комбинации:

  • do/when:включаютdoThrow(…).when(…) / doReturn(…).when(…) / doAnswer(…).when(…)
  • given/will:включаютgiven(…).willReturn(…) / given(…).willAnswer(…)
  • when/then: включаютwhen(…).thenReturn(…) / when(…).thenAnswer(…)

Другие легко понять, сосредоточьтесь на представленииAnswer , AnswerИменно для решения операции маршрутизации, если входной параметр A, результат B, а если C, D. Далее, давайте попрактикуемся, в основном так же, как и в начале, просто замените его на@MockBean

затем используйтеMockitoНаписать метод накладкиvoid bookServiceMockBean(String title), имитируя вышеописанноеBookServiceImplКласс реализации. Однако имитированный компонент автоматически сбрасывается после каждого теста. И не может использоваться для имитации поведения bean-компонентов, работающих во время обновления контекста приложения.

Затем внедрите этот метод в метод тестирования контроллера для тестирования.

6. Другие

ВстроенныйassertjЭто также часто используемое утверждение, API очень дружественное, и оно также передается здесь.bookServiceTest()Простая демонстрация

7. Резюме

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

Соответствующий пояснительный код можно найти вgiteeПолучать.

тоже через меняличный блогПолучите больше галантереи, чтобы поделиться вовремя.

关注公众号:Felordcn获取更多资讯

Личный блог: https://felord.cn