Эта статья была впервые опубликована на моем личном сайте:Использование тестовой среды 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
- Автоматическая настройка Spring Boot, Command-line-Runner
- Понимание автоматической настройки Spring Boot
- Использование аннотации Spring Boot @PropertySource при интеграции Redis
- Как настроить преобразователи HTTP-сообщений в проектах Spring Boot
- Spring Boot интегрирует Mongodb для обеспечения интерфейса Restful.
- Сфера фасоли весной
- Использование шаблона диспетчера событий в проекте Spring Boot
- Методы обработки ошибок, когда Spring Boot предоставляет интерфейсы RESTful
- Настройка собственного стартера в Spring Boot
- Как проекты Spring Boot поддерживают протоколы HTTP и HTTPS
- Как пользовательский стартер Spring Boot настраивает аннотации автоконфигурации
- Использование Mockito в проектах Spring Boot
*** В этом выпуске основное внимание уделяется таким темам, как серверные технологии, устранение неполадок и оптимизация JVM, вопросы на собеседованиях по Java, личностный рост и самоуправление, а читателям предлагается опыт работы и роста передовых разработчиков. получить что-то здесь.