模拟一类spring构造型“Repository”时,Spock mock返回null - 为什么?

时间:2018-01-09 15:13:15

标签: unit-testing spring-mvc spring-boot spock

我刚刚发现使用spock时你可以模拟除“Repository”之外的所有spring构造型(“Component”,“Service”和“Controller”)。 是什么原因?

示例

只要“TestRepository”类具有构造型注释“Repository”,以下示例就不起作用,因为mock的返回值为“null”。如果将构造型注释更改为其他构造型之一,则mock将返回预期的“TestModel”实例。

控制器:

@Controller
class TestController {

private final TestRepository testRepository

TestController(TestRepository testRepository) {
    this.testRepository = testRepository
}

@RequestMapping("/test")
String test(Model model) {
    TestModel testmodel = testRepository.getTestModel()
    ...
}

存储库: (“@ Repository”不起作用,“@ Component”,“@ Service”和“@Controller”工作)

@Repository
class TestRepository {
    TestModel getTestModel() {...}
}

测试:

@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)
        }
    }
}

2 个答案:

答案 0 :(得分:5)

有关详细信息,请参阅Spock Issue 758,简而言之@Repository实例由代理中的spring包装以处理事务,这会破坏模拟交互设置。您可以在@UnwrapAopProxy字段上使用Spock 1.2(仅限SNAPSHOT)和新注释testRepository。或者您可以使用此功能手动打开它。

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
}

答案 1 :(得分:2)

Spock 1.2-SNAPSHOT版本的完整来源:

@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
    }
}