Статьи

Использование Спока для тестирования Spring классов

Как упоминалось в предыдущем посте , Spock — это мощный DSL, построенный на Groovy, который идеально подходит для тестирования TDD и BDD, и в этом посте будет описано, как легко использовать Spock для тестирования классов Spring, в данном случае класс CustomerService из публикации Использование Spring Data для получить доступ к MongoDB . Это также покроет использование Спока для насмешки.

Спок в значительной степени зависит от среды SpringCon TestContext и делает это с помощью аннотации @ContextConfiguration . Это позволяет классу спецификации теста загружать контекст приложения из одного или нескольких местоположений.

Это позволит тестовой спецификации получить доступ к bean-компонентам через аннотацию @Autowired  или @Resource . Тест ниже показывает, как вводитсяЭкземпляр CusotmerService можно протестировать с помощью Spock и Spring TestContext: (Это немного надуманный пример для правильного модульного тестирования класса CustomerService, так как вы создадите класс CustomerService в тесте, а не класс, созданный и введенный Spring.)

package com.city81.mongodb.springdata.dao
 
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
 
import spock.lang.*
 
import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer
 
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {
 
 @Autowired
 CustomerService customerService
  
  
 def setup() {
  customerService.dropCustomerCollection()
 }
  
 def "insert customer"() {
   
  setup:
   
  // setup test class args
  Address address = new Address()
  address.setNumber("81")
  address.setStreet("Mongo Street")
  address.setTown("City")
  address.setPostcode("CT81 1DB")
  
  Account account = new Account()
  account.setAccountName("Personal Account")
  List<Account> accounts = new ArrayList<Account>()
  accounts.add(account)
   
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
  customer.setAccounts(accounts)
 
  when:
  customerService.insertCustomer(customer)
   
  then:
  def customers = customerService.findAllCustomers()
  customers.size == 1
  customers.get(0).name == "Mr Bank Customer"
  customers.get(0).address.street == "Mongo Street"
   
 }
}

Однако проблема с вышеприведенным тестом заключается в том, что MongoDB должен быть запущен и запущен, поэтому для удаления этой зависимости мы можем смоделировать взаимодействие с базой данных. Платформенный фреймворк Спока предоставляет множество функций, которые вы найдете в подобных фреймворках, таких как Mockito.

Усиливается CustomerServiceTest высмеивает CustomerRepository и устанавливает издевались объекта на CustomerService

package com.city81.mongodb.springdata.dao
 
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
 
import spock.lang.*
 
import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer
 
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {
 
 @Autowired
 CustomerService customerService
  
 CustomerRepository customerRepository = Mock()
  
 def setup() {
  customerService.customerRepository = customerRepository
  customerService.dropCustomerCollection()
 }
  
 def "insert customer"() {
   
  setup:
     
  // setup test class args
  Address address = new Address()
  address.setNumber("81")
  address.setStreet("Mongo Street")
  address.setTown("City")
  address.setPostcode("CT81 1DB")
  
  Account account = new Account()
  account.setAccountName("Personal Account")
  List<Account> accounts = new ArrayList<Account>()
  accounts.add(account)
   
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
  customer.setAccounts(accounts)
   
  when:
  customerService.insertCustomer(customer)
   
  then:
  1 * customerRepository.save(customer)
   
 }
  
 def "find all customers"() {
  
  setup:
   
  // setup test class args
  Address address = new Address()
  address.setStreet("Mongo Street")
   
  Customer customer = new Customer()
  customer.setAddress(address)
  customer.setName("Mr Bank Customer")
   
  // setup mocking 
  def mockCustomers = []
  mockCustomers << customer
  customerRepository.findAll() >> mockCustomers
   
  when:
  def customers = customerService.findAllCustomers()
   
  then:
  customers.size() == 1 
  customers.get(0).name == "Mr Bank Customer"
   
 }
  
}

CustomerRepository это путь имени и типа , хотя он может быть выведен только с именем , например ,

def customerRepository = Mock(CustomerRepository)

Внедренный репозиторий customerRepository перезаписывается макетом экземпляра, а затем в тестовой настройке функциональность может быть смоделирована.

В блоке then функции вставки клиентов проверяется количество взаимодействий с методом сохранения customerRepository, а в функции  поиска всех клиентов список возвращаемых клиентов из вызова findAll представляет собой фиктивный список, а не получаемый из база данных.

Более подробную информацию о способах насмешки Спока можно найти на домашней странице проекта .