Cucumber+SpringBoot+JPA测试中Repository返回Null问题求助
Cucumber测试中JPA Repository查询返回Null但数据库存在数据的排查方案
在Cucumber测试里调用JPA Repository的findCustomerShipmentByShipmentNumber方法返回Null,但确认数据库中存在对应数据,怀疑是数据库连接问题,以下是相关代码和实用排查步骤:
相关代码与配置
CucumberConfig.java
package com.xxx.xxx.cucumber; import io.cucumber.spring.CucumberContextConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; @ComponentScan(basePackages = { "com.xxx.xxx.configuration" }) @CucumberContextConfiguration @SpringBootTest public class CucumberConfig { }
CucumberRunner.java
import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; import org.junit.runner.RunWith; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @ContextConfiguration(classes = { CucumberConfig.class }) @RunWith(Cucumber.class) @CucumberOptions( features = "src/test/resources/features", glue={"com.xxx.xxx.cucumber"}, plugin = { "html:target/site/cucumber/cucumber-report.html", "junit:target/site/cucumber/cucumber-report.xml", }) @ActiveProfiles("cucumber") public class CucumberRunner { }
ShipmentBackEndValidationTestsIntegrationTest.java(部分)
@Component public class ShipmentBackEndValidationIntegrationTest implements CucumberStateVariables { private final RestTemplate restTemplate; private static final Logger LOGGER = LoggerFactory.getLogger(ShipmentBackEndValidationIntegrationTest.class); final CucumberUtil cucumberUtil; AppConfig appConfig; CustomerShipmentRepository customerShipmentRepository; @Autowired public ShipmentBackEndValidationIntegrationTest( AppConfig appConfig, CucumberUtil cucumberUtil, OceanRestTemplateHelper oceanRestTemplateHelper, CustomerShipmentRepository customerShipmentRepository ) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { LOGGER.warn("SU: {}", appConfig.getSecurity().getSystemUser()); LOGGER.warn("SUP: {}",appConfig.getSecurity().getSystemUserPassword()); this.appConfig = appConfig; this.cucumberUtil = cucumberUtil; this.restTemplate = oceanRestTemplateHelper.buildRestTemplate(oceanRestTemplateHelper.lrdUserAuth()); this.customerShipmentRepository = customerShipmentRepository; } }
ShipmentBackEndValidationStepDefs.java
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.client.HttpClientErrorException; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Optional; import static org.junit.Assert.*; public class ShipmentBackEndValidationStepDefs extends ShipmentBackEndValidationIntegrationTest { private CustomerShipment requestShipment; private CustomerShipment ResponseShipment; private boolean expectException; private final List<RuntimeException> exceptions = new ArrayList<>(); private static final Logger LOGGER = LoggerFactory.getLogger(CustomerShipmentApiStepDefs.class); private String errorMessage; public ShipmentBackEndValidationStepDefs( AppConfig appConfig, CucumberUtil cucumberUtil, OceanRestTemplateHelper oceanRestTemplateHelper, CustomerShipmentRepository customerShipmentRepository ) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException { super(appConfig, cucumberUtil, oceanRestTemplateHelper, customerShipmentRepository); this.customerShipmentRepository = customerShipmentRepository; } @Given("shipment for {string} branch") public void shipmentWithValidAndIncompleteDataInCarrierDetailsIsCreatedForStringBranch(String branchCode) throws IOException { this.clearExceptionList(); TestDataSerializer.changeTimezoneContextToBranch(branchCode); requestShipment = TestDataSerializer.generateCustomerShipmentFromJson("shipments/CustomerShipment.json"); } @When("the user clicks the save button") public void the_user_clicks_the_save_button() { try{ this.ResponseShipment = saveCustomerShipment(requestShipment); LOGGER.info(String.format("Successfully saved shipment number: ", this.ResponseShipment.getShipmentNumber())); System.out.println("Shipment saved successfully: "+ ResponseShipment.getShipmentNumber()); } catch (HttpClientErrorException err) { this.errorMessage = err.getMessage(); } } @Then("the data is saved to the database") public void dataIsSavedToDatabase1(){ String shipmentNumber = ResponseShipment.getShipmentNumber(); Optional<CustomerShipment> resultShipment = customerShipmentRepository.findCustomerShipmentByShipmentNumber(shipmentNumber); System.out.println("Print -- "+resultShipment); assertTrue(resultShipment.isPresent()); } }
CustomerShipmentRepository.java
package com.xxx.xxx.shipment.repositories; import com.expd.ocean.base_repository.BaseRepository; import com.expd.ocean.shipment.entities.CustomerShipment; import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Optional; import java.util.UUID; @Repository public interface CustomerShipmentRepository extends JpaRepository<CustomerShipment, UUID>, BaseRepository { @EntityGraph(value = "CustomerShipment.fullCustomerShipment", type = EntityGraph.EntityGraphType.LOAD) Optional<CustomerShipment> findCustomerShipmentByShipmentNumber(String shipmentNumber); }
排查步骤
确认测试环境数据库配置
- 检查
application-cucumber.properties/yml中的数据库URL、用户名、密码,确保和你手动查询的是同一个库(很多测试会用内存库或测试专用库,别查错环境)。 - 在
CucumberConfig中注入DataSource,打印dataSource.getConnection().getMetaData().getURL(),直接验证当前连接的数据库。
- 检查
排查事务边界问题
- 如果
saveCustomerShipment是REST接口调用,服务端的事务可能在请求结束后才提交,测试代码中立刻查询会看不到数据。可以改成直接调用Service方法,或者在查询前短暂等待(仅用于验证)。 - 若测试类加了
@Transactional,默认会在测试结束后回滚数据,导致查询不到,可去掉该注解或手动提交事务。
- 如果
修复Repository扫描问题
- 当前
CucumberConfig的@ComponentScan仅扫描com.xxx.xxx.configuration,但Repository在com.xxx.xxx.shipment.repositories,Spring无法扫描到。修改@ComponentScan加入Repository所在包,或添加@EnableJpaRepositories(basePackages = "com.xxx.xxx.shipment.repositories")。 - 在步骤类构造方法中打印
customerShipmentRepository,确认是否成功注入。
- 当前
验证查询逻辑
- 暂时去掉Repository方法上的
@EntityGraph,用简单查询测试,排除EntityGraph配置错误导致的查询失败。 - 打印
shipmentNumber的具体值,和数据库中数据对比,检查大小写、空格等字符匹配问题(部分数据库字符集区分大小写)。
- 暂时去掉Repository方法上的
检查时区影响
- 步骤中调用了
changeTimezoneContextToBranch方法,若CustomerShipment包含时区相关字段,可能因时区不一致导致查询条件不匹配,可临时注释时区切换代码测试。
- 步骤中调用了
内容的提问来源于stack exchange,提问作者Silver555
相关产品推荐
相关产品推荐

