Use Spock testing framework in Spring Boot project

This article first appeared personal website: Use Spock testing framework in Spring Boot project

Spock framework is based on testing framework Groovy language, Groovy and Java have good interoperability, and therefore can be used in Spring Boot project in the framework write elegant, efficient and DSL of test cases. Spock by @RunWith annotation JUnit framework used in conjunction with, additionally, may be Spock and the Mockito ( the Spring --Mockito the Boot application tests used together).

In this section we will use Spock, write some test cases (including testing and testing of the Controller of the Repository) together Mockito, use Spock's next experience.

Real

  • According to Building an Application with Spring Boot described in this article, the Spring-the Boot-Maven-plugin This plugin also supports the Groovy language in Spring Boot framework.
  • Add rely Spock in the framework of the pom file
<!-- 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>
  • Create a groovy folder under src / test directory, create com / test / bookpub package in the groovy folder.
  • Added at a resources directory packt-books.sql file as follows:
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);
  • In com / test / bookpub create a directory SpockBookRepositorySpecification.groovy file, reads:
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
  }
}
  • Implementation of test cases, test passed
  • The next test at Spock how to work with mock objects, the previous article, we have TestMockBeansConfig defined class PublisherRepository the Spring Bean, as shown below, due to the presence @Primary, making Spring Boot priority use when running the test case Mockito examples of the simulated frame.
@Configuration
@UsedForTesting
public class TestMockBeansConfig {
    @Bean
    @Primary
    public PublisherRepository createMockPublisherRepository() {
        return Mockito.mock(PublisherRepository.class);
    }
}
  • Add getBooksByPublisher BookController.java interface, as shown in the following code:
@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();
}
  • In SpockBookRepositorySpecification.groovy adding the corresponding test case file,
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)
}
  • Run the test case, the test can be found by, the controller converts the object into a string loaded JSON HTTP response body, dependent Jackson library to perform the conversion, there may be a circular dependency problem - relationship model, a book-dependent a publishing house, publishers have included a number of books, in the implementation of the conversion, if not special treatment, it will cycle resolution. We here by @JsonBackReference prevent circular dependencies comment.

analysis

As can be seen, you can write elegant and powerful test code by Spock framework.

First look SpockBookRepositorySpecification.groovy file, the class inherits from Specification class, this class is telling JUnit test class. View Specification class source code, it can be found @RunWith (Sputnik.class) annotation modification, this comment is a bridge between Spock and of JUnit. In addition to guiding JUnit, Specification class also provides a number of test methods and mocking support.

Note: See this document on Spock: Spock Framework Reference Documentation

The "art unit testing", mentions the test unit comprising: preparing a test data, the test method to be executed, the results of three determination steps. Spock in these steps by a test setup, expect, when, and then label the like.

  • setup: This block is used to define the variables, the test preparation data, and the like construct mock object;
  • expect: generally used after setup with a block that contains some assert statements, checks prepared in the test environment setup block
  • when: the calling method to be tested in this block;
  • then: with the general use after when, he can assert contain statements, exception checking statements and so on, for the method to be tested to check whether the execution results in line with expectations;
  • cleanup: modify the setup used to clear the block on the environment to do, is about to roll back the current modify test cases, we perform the reset operation to publisherRepository objects in this case.

Spock also provides a setup () and cleanup () method, some preparation for the use of all test cases and cleanup actions, such as in this example we use the setup method: (1) mock the web runtime environment that can accept http request; (2) loading packt-books.sql file, import predefined test data. Mock web environment only once, so use this flag to control sharedSetupDone.

@Transactional annotation can be achieved by operating the transaction, if a method is modified to the comments, the associated setup () method, cleanup () methods are defined to perform operations in a transaction: either all succeed or roll back to initial state. We rely on this method to ensure that the database is clean, but also to avoid each enter the same data.

Spring Boot 1.x series

  1. Spring Boot automatic configuration, Command-line-Runner
  2. Understanding Automatic configuration of Spring Boot
  3. Spring Boot of @PropertySource notes in the integration of Redis
  4. Spring Boot project, how to customize HTTP message converter
  5. Spring Boot Restful interface to provide integrated Mongodb
  6. Spring bean in scope
  7. Spring Boot event dispatcher used in the project mode
  8. Error handling practices when Spring Boot provides RESTful interface
  9. Spring Boot of combat customize their starter
  10. How Spring Boot project supports both HTTP and HTTPS protocols
  11. How Spring Boot starter customized settings to automatically configure annotation
  12. Spring Boot used in the project Mockito

This focus on the number of back-end technology, JVM troubleshooting and optimization, Java interview questions, personal growth and self-management, and other topics, providing front-line developers work and growth experience for the reader, you can expect to gain something here.
Jwadu

Guess you like

Origin www.cnblogs.com/javaadu/p/11748473.html