端点和存储库的 spock 测试

spock testing of endpoint and repository

正在进行我的 Spring 2.67 和 Spock 2.1-groovy-3.0 测试。我有基本的测试工作,但现在尝试一些集成测试但没有成功。我有一个控制器:

   private ApiService apiService;

   @Autowired
   public ApiController(ApiService apiService) {

        this.apiService = apiService;
    }

    @GetMapping("api/{scannedId}")
    @ResponseBody
    public ResponseEntity getScannedId(@PathVariable String scannedId) {

        try {
            logger.info("ApiKey Controller received GET /api/" + scannedId);
            ApiKey found = apiService.retrieveValidApiKey(scannedId);
            ...
          }
...

api服务有:

 private ApiRepository apiRepository;

@Autowired
public ApiService(ApiRepository apiRepository) {
    this.apiRepository = apiRepository;
}

public ApiKey retrieveValidApiKey(String uuid) {

    ApiKey anApi = apiRepository.getApiKeyByApiKey(uuid);
    if (anApi == null) {
        logger.info("ApiService.retrieveValidApiKey({}) failed to find a matching ApiKey", uuid);
        return null;
    }

我有一个 Spock 测试,它使用两个值对数据库进行播种,然后成功调用 /api 端点。我在测试中有代码确认插入了两个值,但是当调用实际的 ApiService class 时,找不到它们:

  @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase
class ApiControllerTest extends Specification {

    @Shared Logger logger = LoggerFactory.getLogger(this.getClass())

    @Autowired
    ApiController apiController

    @Autowired
    ApiRepository apiRepository

 @Transactional
 def "GET by scannedId using apikey #apiKey should be #resultCode"() {
        given:

        def foundList = apiRepository.findAll()
        logger.info("{} apiKeys in repository", foundList.size())

        for (int i = 0; i < foundList.size(); i++) {
            logger.info("Found ApiKey #{} apiKey: {} & uuid: {}", i, foundList.get(i).apiKey, foundList.get(i).uuid)
        }

        when:
        def foundListCount = apiRepository.getApiKeyByApiKey(apiKey)
        logger.info("FoundList: {}", foundListCount)
        ResponseEntity<ApiKey> result = restTemplate.getForEntity( "/api/{scannedId}", ApiKey.class, apiKeyValue1)
        logger.info("TestRestTemplate returned apikey: {}", result)

        then:
        assert result.getStatusCode() == resultCode

        where:
        apiKey       || resultCode
        "testApiKey3" || HttpStatus.NOT_FOUND
        apiKeyValue1 || HttpStatus.OK
        apiKeyValue2 || HttpStatus.OK
    }

def setup() {
        def apiKey1 = new ApiKey(apiKey: apiKeyValue1, uuid: uuid1, beginDate: beginDate1, endDate: endDate1)
        def apiKey2 = new ApiKey(apiKey: apiKeyValue2, uuid: uuid2, beginDate: beginDate2, endDate: endDate2)
        apiRepository.saveAndFlush(apiKey1)
        apiRepository.saveAndFlush(apiKey2)
    }

当我 运行 测试时,测试方法中的记录器吐出所有持久值。但是测试失败了,因为 ApiService.getScannedId 失败了,因为它没有看到测试设置中保留的值。

我无法使用 @DataJpaTest,因为当时没有加载 ApplicationContext,因此端点失败。

我不确定为什么 Spock 会看到通过存储库保留的值,但 ApiService 却看不到。这是上下文问题吗?如果可能的话,我真的很想在没有模拟的情况下进行测试。

问题是您的测试用 @Transactional 注释,这意味着只有在该方法中 运行 的东西才能看到数据。您发送的其余请求将由另一个无权访问事务的线程处理,因此不会看到数据。

如果你想让它工作,你必须删除注释,但是你还必须在测试结束时手动清理插入的数据/cleanup(),因为你不能'不依赖事务回滚