为何标注@BeforeAll的setup方法未将ShippingAddress对象存入数据库?
问题分析与解决方案
可能的触发原因
- 事务未实际提交:
@Rollback注解依赖@Transactional才能生效,你的setup方法仅添加了@Rollback(false)但未声明事务,导致save操作的事务默认被回滚,数据根本没写入数据库。 - 实体ID策略冲突:如果
ShippingAddress实体的ID使用自动生成策略(比如@GeneratedValue(strategy = GenerationType.IDENTITY)),手动设置的ID"1"不会被数据库认可,实际生成的ID可能不是"1",测试时自然找不到对应数据。 - H2内存数据库特性:若使用内存模式的H2数据库,事务未提交的情况下,测试方法启动时数据库会回到初始状态,之前插入的数据不存在。
具体修正步骤
1. 给setup方法补全事务注解
确保数据能真正提交到数据库:
@BeforeAll @Transactional @Rollback(value = false) public void setup() { testShippingAddress = shippingAddressRepository.save(new ShippingAddress("1","0722123443","Popescu","Ana","aleea lalelelor", "Romania","Sv","2112",null)); System.out.println("保存后的收货地址ID:" + testShippingAddress.getId()); // 打印确认ID是否匹配预期 testBillingAddress = billingAddressRepository.save(new BillingAddress("1", "0722123443","Popescu","Ana","aleea lalelelor", "Romania","Sv","2112",null)); }
2. 检查实体ID配置
打开ShippingAddress实体类,确认ID注解是否允许手动赋值:
@Entity public class ShippingAddress { @Id // 若需要手动指定ID,不要添加@GeneratedValue注解,或设置策略为ASSIGN private String id; // 其他字段... }
如果必须使用自动生成策略,不要手动设置ID,改用save返回对象的实际ID:
// setup方法中不手动设置ID testShippingAddress = shippingAddressRepository.save(new ShippingAddress(null,"0722123443","Popescu","Ana","aleea lalelelor", "Romania","Sv","2112",null)); // 测试时使用生成后的真实ID MvcResult mvcResult = mockMvc.perform(createPostRequest(OrdersController.PATH, new CreateOrderReqDTO(OrderStatus.PAID, 3, 100.0, 100.0, 5.0, testShippingAddress.getId(), testBillingAddress.getId(), "1", "1"))) .andReturn();
3. 确认H2数据库配置
保证application.yml中的H2配置能保留内存数据:
spring: datasource: url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE driver-class-name: org.h2.Driver username: sa password:
DB_CLOSE_DELAY=-1可以防止内存数据库在连接关闭时清空数据。
完整修正后的测试类示例
@ExtendWith(SpringExtension.class) @SpringBootTest(classes = {OrdersApiApplication.class, H2JpaConfig.class}) @AutoConfigureMockMvc @TestInstance(TestInstance.Lifecycle.PER_CLASS) @TestClassOrder(ClassOrderer.OrderAnnotation.class) @TestPropertySource("classpath:application.yml") class OrdersControllerTest extends GenericIntegrationTest { @Autowired private MockMvc mockMvc; @Autowired private ShippingAddressRepository shippingAddressRepository; @Autowired private BillingAddressRepository billingAddressRepository; private static ShippingAddress testShippingAddress; private static BillingAddress testBillingAddress; @BeforeAll @Transactional @Rollback(value = false) public void setup() { // 若实体允许手动设置ID,直接使用指定值 testShippingAddress = shippingAddressRepository.save(new ShippingAddress("1","0722123443","Popescu","Ana","aleea lalelelor", "Romania","Sv","2112",null)); System.out.println("保存后的收货地址:" + testShippingAddress); testBillingAddress = billingAddressRepository.save(new BillingAddress("1", "0722123443","Popescu","Ana","aleea lalelelor", "Romania","Sv","2112",null)); } @Nested class CreateOrderTests { @Nested class CreateProductTests { private ObjectMapper mapper = new ObjectMapper(); @Test void shouldCreateOrderSuccessfully() throws Exception { // 若实体ID是自动生成,使用testShippingAddress.getId()而非硬编码"1" MvcResult mvcResult = mockMvc .perform(createPostRequest(OrdersController.PATH, new CreateOrderReqDTO(OrderStatus.PAID, 3, 100.0, 100.0, 5.0, testShippingAddress.getId(), testBillingAddress.getId(), "1", "1"))) .andReturn(); OrderDTO response = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); assertEquals(100.0, response.getTotal()); assertEquals(100.0, response.getGrandTotal()); } } } }
内容的提问来源于stack exchange,提问作者Anamaria Afanasov
相关产品推荐
相关产品推荐

