Spock 1.2 Spring Integration Test annotations SpringBean, SpringSpy, UnwrapAopProxy
//Just a snippet to show how to include Spock 1.2 before it has been released | |
repositories { | |
maven { | |
//Required until Spock 1.2 is released out of snapshot | |
url 'https://oss.sonatype.org/content/repositories/snapshots/' | |
} | |
} | |
dependencies { | |
testCompile("org.springframework.boot:spring-boot-starter-test") //for AopTestUtils | |
testCompile("org.spockframework:spock-core:1.2-groovy-2.4-SNAPSHOT") | |
testCompile("org.spockframework:spock-spring:1.2-groovy-2.4-SNAPSHOT") | |
} |
import org.springframework.test.util.AopTestUtils | |
/** Showing how to unwrap the AOP proxy manually to reuse the cached Spring context config */ | |
@Import([IntegrationTestMockingConfig]) | |
class PersonControllerIntProxiedTest extends Specification { | |
@Autowired MockMvc mvc | |
/** A simple mock can just be autowired */ | |
@Autowired ExternalRankingService externalRankingServiceMock | |
/** A Proxied mock must first be AOP unwrapped */ | |
@Autowired ValidatedExternalRankingService proxiedValidatedExternalRankingService | |
ValidatedExternalRankingService validatedExternalRankingService | |
void setup() { | |
//Manually unwrap the AOP proxy | |
validatedExternalRankingService = AopTestUtils.getUltimateTargetObject(proxiedValidatedExternalRankingService) | |
} | |
def "GetValidatedRank"() { /*Test goes here...*/ } | |
} |
@SpringBootTest | |
@AutoConfigureMockMvc | |
class PersonControllerIntSpock12ProxiedSpec extends Specification { | |
@Autowired MockMvc mvc | |
/** | |
* SpringSpy will wrap the Spring injected Service with a Spy | |
* UnwrapAopProxy will remove the cglib @Validated proxy | |
*/ | |
@SpringSpy | |
@UnwrapAopProxy | |
ValidatedExternalRankingService validatedExternalRankingService | |
def "GetValidatedRank"() { | |
when: 'Calling getRank for a known seed data entity' | |
MvcResult mvcResult = mvc.perform(get("/persons/1/validatedRank").contentType(APPLICATION_JSON)) | |
.andExpect(status().is2xxSuccessful()).andReturn() | |
then: 'we define the mock for the external service' | |
1 * validatedExternalRankingService.getRank(_) >> { | |
new Rank(level: 1, classification: 'Captain') | |
} | |
noExceptionThrown() | |
when: 'inspecting the contents' | |
def resultingJson = mvcResult.response.contentAsString | |
then: 'the result contains a mix of mocked service data and actual wired component data' | |
resultingJson == 'Capt James Kirk ~ Captain:Level 1' | |
} | |
} |
@SpringBootTest | |
@AutoConfigureMockMvc | |
class PersonControllerIntSpock12Spec extends Specification { | |
@Autowired MockMvc mvc | |
/** SpringBean will put the mock into the spring context */ | |
@SpringBean | |
ExternalRankingService externalRankingService = Mock() | |
def "GetRank"() { | |
when: 'Calling getRank for a known seed data entity' | |
MvcResult mvcResult = mvc.perform(get("/persons/1/rank").contentType(APPLICATION_JSON)) | |
.andExpect(status().is2xxSuccessful()).andReturn() | |
then: 'we define the mock for JUST the external service' | |
1 * externalRankingService.getRank(_) >> { | |
new Rank(level: 1, classification: 'Captain') | |
} | |
noExceptionThrown() | |
when: 'inspecting the contents' | |
def resultingJson = mvcResult.response.contentAsString | |
then: 'the result contains a mix of mocked service data and actual wired component data' | |
resultingJson == 'Capt James Kirk ~ Captain:Level 1' | |
} | |
} |
//An example error seen when trying to Spy a Spring Proxied object, but forgetting to unwrap it first | |
// Notice the lowercase/uppercase 'v' in validatedExternalRankingService that somewhat points to | |
// the mock being a slightly different object. | |
Too few invocations for: | |
1 * validatedExternalRankingService.getRank(_) >> { | |
new Rank(level: 1, classification: 'Captain') | |
} (0 invocations) | |
Unmatched invocations (ordered by similarity): | |
1 * ValidatedExternalRankingService.getRank(com.objectpartners.eskens.entities.Person(1, James, Kirk, Capt)) |
/** This class is @Validated, which makes it a Spring AOP proxied service */ | |
@Service | |
@Validated | |
class ValidatedExternalRankingService { | |
Rank getRank(Person person) { throw new RuntimeException('This feature is not yet implemented.') } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment