Использование тестовой среды Spock в проекте Spring Boot

Spring Boot

Эта статья была впервые опубликована на моем личном сайте:Использование тестовой среды Spock в проекте Spring Boot

Платформа Spock — это тестовая среда, основанная на языке Groovy. Groovy и Java обладают хорошей функциональной совместимостью, поэтому вы можете использовать эту среду для написания элегантных и эффективных тестовых примеров на основе DSL в проектах Spring Boot. Спок через@RunWithАннотации используются совместно с фреймворком JUnit, кроме того, Spock можно использовать и с Mockito (Тестирование приложения Spring Boot — Mockito) использовать вместе.

В этом разделе мы будем использовать Spock и Mockito для написания некоторых тестовых случаев (включая тест контроллера и тест репозитория) и почувствуем использование Spock.

настоящий бой

  • согласно сBuilding an Application with Spring BootОписание этой статьи,spring-boot-maven-pluginЭтот подключаемый модуль также поддерживает использование языка Groovy в среде Spring Boot.
  • Добавить зависимости инфраструктуры Spock в файл pom
<!-- test -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.spockframework</groupId>
   <artifactId>spock-core</artifactId>
   <scope>test</scope></dependency>
<dependency>
   <groupId>org.spockframework</groupId>
   <artifactId>spock-spring</artifactId>
   <scope>test</scope>
</dependency>

  • Создайте папку groovy в каталоге src/test и создайте пакет com/test/bookpub в папке groovy.
  • Добавьте в каталог ресурсовpackt-books.sqlфайл со следующим содержимым:
INSERT INTO author (id, first_name, last_name) VALUES (5, 'Shrikrishna', 'Holla');
INSERT INTO book (isbn, title, author, publisher) VALUES ('978-1-78398-478-7', 'Orchestrating Docker', 5, 1);
INSERT INTO author (id, first_name, last_name) VALUES (6, 'du', 'qi');
INSERT INTO book (isbn, title, author, publisher) VALUES ('978-1-78528-415-1', 'Spring Boot Recipes', 6, 1);

  • существуетcom/test/bookpubСоздано в каталогеSpockBookRepositorySpecification.groovyфайл, содержание:
package com.test.bookpubimport com.test.bookpub.domain.Author

import com.test.bookpub.domain.Book
import com.test.bookpub.domain.Publisher
import com.test.bookpub.repository.BookRepository
import com.test.bookpub.repository.PublisherRepository
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.SpringApplicationContextLoader
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.web.WebAppConfiguration
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import spock.lang.Sharedimport spock.lang.Specification
import javax.sql.DataSourceimport javax.transaction.Transactional

import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebAppConfiguration
@ContextConfiguration(classes = [BookPubApplication.class,
 TestMockBeansConfig.class],loader = SpringApplicationContextLoader.class)
class SpockBookRepositorySpecification extends Specification {
    @Autowired
    private ConfigurableApplicationContext context;
    @Shared
    boolean sharedSetupDone = false;
    @Autowired
    private DataSource ds;
    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private PublisherRepository publisherRepository;
    @Shared
    private MockMvc mockMvc;

    void setup() {
        if (!sharedSetupDone) {
            mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
            sharedSetupDone = true;
        }
        ResourceDatabasePopulator populator = new 
               ResourceDatabasePopulator(context.getResource("classpath:/packt-books.sql"));
        DatabasePopulatorUtils.execute(populator, ds);
    }

    @Transactional
    def "Test RESTful GET"() {
        when:
        def result = mockMvc.perform(get("/books/${isbn}"));
  
        then:
        result.andExpect(status().isOk()) 
       result.andExpect(content().string(containsString(title)));

       where:
       isbn              | title
      "978-1-78398-478-7"|"Orchestrating Docker"
      "978-1-78528-415-1"|"Spring Boot Recipes"
    }

    @Transactional
    def "Insert another book"() {
      setup:
      def existingBook = bookRepository.findBookByIsbn("978-1-78528-415-1")
      def newBook = new Book("978-1-12345-678-9", "Some Future Book",
              existingBook.getAuthor(), existingBook.getPublisher())

      expect:
      bookRepository.count() == 3

      when:
      def savedBook = bookRepository.save(newBook)

      then:
      bookRepository.count() == 4
      savedBook.id > -1
  }
}

  • Выполните тестовый пример, тест проходит
  • Затем попробуйте, как Spock работает с фиктивными объектами. В предыдущей статье мыTestMockBeansConfigопределено в классеPublisherRepositorySpring Bean, как показано ниже, из-за существования @Primary, Spring Boot предпочтительно использует экземпляр, смоделированный платформой Mockito, при выполнении тестового примера.
@Configuration
@UsedForTesting
public class TestMockBeansConfig {
    @Bean
    @Primary
    public PublisherRepository createMockPublisherRepository() {
        return Mockito.mock(PublisherRepository.class);
    }
}

  • Добавьте интерфейс getBooksByPublisher в BookController.java, код выглядит следующим образом:
@Autowired
public PublisherRepository publisherRepository;

@RequestMapping(value = "/publisher/{id}", method = RequestMethod.GET)
public List<Book> getBooksByPublisher(@PathVariable("id") Long id) {
    Publisher publisher = publisherRepository.findOne(id);
    Assert.notNull(publisher);
    return publisher.getBooks();
}

  • существуетSpockBookRepositorySpecification.groovyДобавьте соответствующий тестовый пример в файл,
def "Test RESTful GET books by publisher"() {
    setup:
    Publisher publisher = new Publisher("Strange Books")
    publisher.setId(999)
    Book book = new Book("978-1-98765-432-1",
            "Mytery Book",
            new Author("Jhon", "Done"),
            publisher)
    publisher.setBooks([book])
    Mockito.when(publisherRepository.count()).
            thenReturn(1L);
    Mockito.when(publisherRepository.findOne(1L)).
            thenReturn(publisher)

    when:
    def result = mockMvc.perform(get("/books/publisher/1"))

    then:
    result.andExpect(status().isOk())
    result.andExpect(content().string(containsString("Strange Books")))

    cleanup:
    Mockito.reset(publisherRepository)
}

  • Запустите тестовый пример и обнаружите, что тест может быть пройден.Когда контроллер преобразует объект в строку JSON и загружает тело ответа HTTP, полагаясь на библиотеку Джексона для выполнения преобразования, может возникнуть проблема циклической зависимости - в отношениях модели , книга зависит от издательства, издательство содержит несколько книг, при выполнении конвертации, если не производится специальная обработка, она будет анализироваться в цикле. мы проходим здесь@JsonBackReferenceАннотации предотвращают циклические зависимости.

анализировать

Видно, что элегантный и мощный тестовый код можно написать с помощью фреймворка Spock.

Сначала взгляните на файл SpockBookRepositorySpecification.groovy, который наследуется от класса Specification и сообщает JUnit, что этот класс является тестовым. Глядя на исходный код класса Specification, вы можете обнаружить, что он изменен аннотацией @RunWith(Sputnik.class), которая является мостом между Spock и JUnit. Помимо начальной загрузки JUnit, класс Specification предоставляет множество тестовых методов и поддержку имитации.

Примечание. Документация по Spock находится здесь:Spock Framework Reference Documentation

Согласно книге «Искусство модульного тестирования», модульное тестирование включает три этапа: подготовку тестовых данных, выполнение тестируемого метода и оценку результата выполнения. Спок помещает эти шаги в тестовый пример с такими тегами, как установка, ожидание, когда и затем.

  • настройка: этот блок используется для определения переменных, подготовки тестовых данных, создания фиктивных объектов и т. д.;
  • Ожидание: обычно используется после блока настройки, включая некоторые утверждения, для проверки тестовой среды, подготовленной в блоке настройки.
  • когда: в этом блоке вызывается тестируемый метод;
  • then : обычно используется после того, когда и может включать операторы утверждения, операторы проверки исключений и т. д., чтобы проверить, соответствует ли результат тестируемого метода ожидаемому после выполнения;
  • очистка: используется для очистки изменений, внесенных в среду в блоке настройки, то есть для отката изменений в текущем тестовом примере.В этом примере мы сбрасываем объект publisherRepository.

Spock также предоставляет методы setup () и cleanup () для выполнения некоторых действий по подготовке и очистке для всех тестовых случаев.Например, в этом примере мы используем метод установки: (1) Смоделируйте среду выполнения веб-среды, которая может принимать HTTP-запросы. ; (2) Загрузите файл packt-books.sql и импортируйте предопределенные тестовые данные. Веб-среде требуется Mock только один раз, поэтому для управления используйте флаг sharedSetupDone.

Транзакционные операции могут быть реализованы с помощью аннотации @Transactional.Если метод изменен этой аннотацией, все связанные с ним методы setup() и cleanup() определяются в транзакции для выполнения операций: либо все выполняются успешно, либо возвращаются к исходному состоянию. Мы полагаемся на этот метод, чтобы содержать базу данных в чистоте и избегать ввода одних и тех же данных каждый раз.

Весенняя загрузка серии 1.x

  1. Автоматическая настройка Spring Boot, Command-line-Runner
  2. Понимание автоматической настройки Spring Boot
  3. Использование аннотации Spring Boot @PropertySource при интеграции Redis
  4. Как настроить преобразователи HTTP-сообщений в проектах Spring Boot
  5. Spring Boot интегрирует Mongodb для обеспечения интерфейса Restful.
  6. Сфера фасоли весной
  7. Использование шаблона диспетчера событий в проекте Spring Boot
  8. Методы обработки ошибок, когда Spring Boot предоставляет интерфейсы RESTful
  9. Настройка собственного стартера в Spring Boot
  10. Как проекты Spring Boot поддерживают протоколы HTTP и HTTPS
  11. Как пользовательский стартер Spring Boot настраивает аннотации автоконфигурации
  12. Использование Mockito в проектах Spring Boot

*** В этом выпуске основное внимание уделяется таким темам, как серверные технологии, устранение неполадок и оптимизация JVM, вопросы на собеседованиях по Java, личностный рост и самоуправление, а читателям предлагается опыт работы и роста передовых разработчиков. получить что-то здесь.javaadu