I just found out that when using spock you can mock all spring stereotypes ("Component", "Service" and "Controller") except of "Repository". What is the reason?
Example:
The following example does not work as long as the "TestRepository" class has the stereotype annotation "Repository" because the return value of the mock is "null". If changing the stereotype annotation to one of the other stereotypes the mock returns the expected instance of "TestModel".
Controller:
@Controller
class TestController {
private final TestRepository testRepository
TestController(TestRepository testRepository) {
this.testRepository = testRepository
}
@RequestMapping("/test")
String test(Model model) {
TestModel testmodel = testRepository.getTestModel()
...
}
Repository: ("@Repository" does not work, "@Component", "@Service" and "@Controller" work)
@Repository
class TestRepository {
TestModel getTestModel() {...}
}
Test:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc(secure = false)
@DirtiesContext
class TestControllerSpec extends Specification {
@Autowired
MockMvc mockMvc
@Autowired
TestRepository testRepository
def "test"() {
testRepository.getTestModel >> new TestModel()
}
@TestConfiguration
static class MockConfig {
def factory = new DetachedMockFactory()
@Bean
@Primary
TestRepository testRepository() {
factory.Mock(TestRepository)
}
}
}
See Spock Issue 758 for more details, in short @Repository
instances are wrapped in by spring in a proxy to handle transactions, this breaks the mock interactions setup. You can either use Spock 1.2 (currently SNAPSHOT only) and the new annotation @UnwrapAopProxy
on the testRepository
field. Or you can use this function to unwrap it manually.
public static <T> T getTargetObject(Object proxy) throws Exception {
if (AopUtils.isAopProxy(proxy)) {
return (T) ((Advised) proxy).getTargetSource().getTarget();
} else {
return (T) proxy;
}
}
def "test"() {
given:
TestRepository mock = getTargetObject(testRepository)
mock.getTestModel() >> new TestModel()
expect:
testRepository.getTestModel() != null
}
The full source for a Spock 1.2-SNAPSHOT version:
@SpringBootTest
@AutoConfigureMockMvc
class TestControllerSpec extends Specification {
@Autowired
MockMvc mockMvc
@SpringSpy
@UnwrapAopProxy
TestRepository testRepository
def "test"() {
when:
//def result = mockMvc.get(...) //implement me
then:
1 * testRepository.getTestModel >> new TestModel()
result
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With