I am developing in Groovy and I am trying to write a Spock unit test for the following use of Spring's RestTemplate...
Included are my request callback and response extractors, and my initialization class of the RestTemplate bean. I am using the ResponseExtractor to stream the response from GET myurl/
and copy it to a file. The RequestCallback is simply setting some headers on the request.
class RestTemplateConfig() {
@Bean(name = 'myRestTemplate')
RestTemplate getMyRestTemplate() {
RestTemplate restTemplate = new RestTemplateBuilder().build()
return restTemplate
}
}
class MyClass() {
@Autowired
@Qualifier('myRestTemplate')
RestTemplate restTemplate
File getFile() {
ResponseExtractor<Void> responseExtractor = { ClientHttpResponse response ->
// do something with the response
// in this case, the response is an input stream so we copy the input stream to a file
myFile = response.getBody() // roughly, in a psuedocode-ish way
return null
}
RequestCallback requestCallback = { ClientHttpRequest request ->
request.getHeaders().setAccept([MediaType.APPLICATION_JSON])
}
File myFile
// get my file data
restTemplate.execute('myurl/', HttpMethod.GET, requestCallback, responseExtractor)
return myFile
}
}
Spring framework docs for that particular execute(...)
method: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#execute-java.net.URI-org.springframework.http.HttpMethod-org.springframework.web.client.RequestCallback-org.springframework.web.client.ResponseExtractor-
How do I mock out what's happening in these closures? Specifically, I'm interested in mocking out my response extractor because my current test always returns myFile
as null.
when:
// do stuff
then:
1 * restTemplate.execute('myurl/, HttpMethod.GET, _, _) // how can I mock out the expected response here?
0 * _
myFile != null // this fails because myFile is null
After you updated your sample code as I requested, I can see more clearly now. You are suffering from a typical (non-)testability problem: Your method getFile
does more than just getting a file. It instantiates two dependencies as local variables, making them unmockable and consequently the whole method mostly untestable.
So you want to refactor for better testability so as to be able to use one testing method I mentioned in my first comment:
- If the
requestCallback
andresponseExtractor
can be injected via constructor or setter, you can inject mocks.- If they are created by some kind of factory class, you can stub that class.
- In case of a factory method inside the class under test itself you can use a spy on the class and stub the factory method.
For a more general discussion of testability and how tests drive application design, see my other answer here, sections "General comments" and "Update".
If any of this is unclear, feel free to ask related(!) follow-up questions.