The Spring module enables integration with Spring TestContext Framework.
It supports the following spring annotations @ContextConfiguration
and @ContextHierarchy
. Furthermore, it supports the meta-annotation @BootstrapWith
and so any annotation that is annotated with @BootstrapWith
will also work, such as @SpringBootTest
, @WebMvcTest
.
Mocks
Spock 1.1 introduced the DetachedMockFactory
and the SpockMockFactoryBean
which allow the creation of Spock mocks outside of a specification.
Note
|
Although the mocks can be created outside of a specification, they only work inside the scope of a specification. So don’t perform any actions on them until they are attached to one. |
Java Config
class DetachedJavaConfig {
def mockFactory = new DetachedMockFactory()
@Bean
GreeterService serviceMock() {
return mockFactory.Mock(GreeterService)
}
@Bean
GreeterService serviceStub() {
return mockFactory.Stub(GreeterService)
}
@Bean
GreeterService serviceSpy() {
return mockFactory.Spy(GreeterServiceImpl)
}
@Bean
FactoryBean<GreeterService> alternativeMock() {
return new SpockMockFactoryBean(GreeterService)
}
}
XML
Spock has spring namespace support, so if you declare the spock namespace with xmlns:spock="http://www.spockframework.org/spring"
you get access to the convenience functions for creating mocks.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spock="http://www.spockframework.org/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.spockframework.org/spring http://www.spockframework.org/spring/spock.xsd">
<spock:mock id="serviceMock" class="org.spockframework.spring.docs.GreeterService"/> (1)
<spock:stub id="serviceStub" class="org.spockframework.spring.docs.GreeterService"/> (2)
<spock:spy id="serviceSpy" class="org.spockframework.spring.docs.GreeterServiceImpl"/> (3)
<bean id="someExistingBean" class="java.util.ArrayList"/> (4)
<spock:wrapWithSpy ref="someExistingBean"/> (4)
<bean id="alternativeMock" class="org.spockframework.spring.xml.SpockMockFactoryBean"> (5)
<constructor-arg value="org.spockframework.spring.docs.GreeterService"/>
<property name="mockNature" value="MOCK"/> (6)
</bean>
</beans>
-
Creates a
Mock
-
Creates a
Stub
-
Creates a
Spy
-
Wraps an existing bean with a
Spy
. Fails fast if referenced bean is not found. -
If you don’t want to use the special namespace support you can create the beans via the
SpockMockFactoryBean
-
The
mockNature
can beMOCK
,STUB
, orSPY
and defaults toMOCK
if not declared.
Usage
To use the mocks just inject them like any other bean and configure them as usual.
@Autowired @Named('serviceMock')
GreeterService serviceMock
@Autowired @Named('serviceStub')
GreeterService serviceStub
@Autowired @Named('serviceSpy')
GreeterService serviceSpy
@Autowired @Named('alternativeMock')
GreeterService alternativeMock
def "mock service"() {
when:
def result = serviceMock.greeting
then:
result == 'mock me'
1 * serviceMock.getGreeting() >> 'mock me'
}
def "sub service"() {
given:
serviceStub.getGreeting() >> 'stub me'
expect:
serviceStub.greeting == 'stub me'
}
def "spy service"() {
when:
def result = serviceSpy.greeting
then:
result == 'Hello World'
1 * serviceSpy.getGreeting()
}
def "alternatice mock service"() {
when:
def result = alternativeMock.greeting
then:
result == 'mock me'
1 * alternativeMock.getGreeting() >> 'mock me'
}
Spring Boot
The recommended way to use Spock mocks in @WebMvcTest
tests, is to use an embedded config annotated with @TestConfiguration
and to create the mocks using the DetachedMockFactory
.
@WebMvcTest
class WebMvcTestIntegrationSpec extends Specification {
@Autowired
MockMvc mvc
@Autowired
HelloWorldService helloWorldService
def "spring context loads for web mvc slice"() {
given:
helloWorldService.getHelloMessage() >> 'hello world'
expect: "controller is available"
mvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(status().isOk())
.andExpect(content().string("hello world"))
}
@TestConfiguration
static class MockConfig {
def detachedMockFactory = new DetachedMockFactory()
@Bean
HelloWorldService helloWorldService() {
return detachedMockFactory.Stub(HelloWorldService)
}
}
}
For more examples see the specs in the codebase and boot examples.
Scopes
Spock ignores bean that is not a singleton
(in the singleton
scope) by default. To enable mocks to work for scoped beans
you need to add @ScanScopedBeans
to the spec and make sure that the scope allows access to the bean during the setup phase.
Note
|
The request and session scope will throw exceptions by default, if there is no active request/session.
|
You can limit the scanning to certain scopes by using the value
property of @ScanScopedBeans
.