我被方法周围的单元测试困住了@Transactional
。问题是我无法测试内部的回滚机制@DataJpaTest
。
这是我的简化示例应用程序:
@RestController
public class MyController {
private final MyRepository myRepository;
private final MyService myService;
public MyController(MyRepository myRepository, MyService myService) {
this.myRepository = myRepository;
this.myService = myService;
}
@GetMapping
@Transactional
public String justForTest() {
var myEntity = new MyEntity().setStatus("NEW");
myRepository.save(myEntity);
try {
myService.throwsAnRuntimeException();
// on service succeed
myEntity.setStatus("SUCCESS");
} catch (Exception e) {
// on service fail
myEntity.setStatus("FAIL");
throw e;
} finally {
myRepository.save(myEntity);
}
return "this is the end";
}
}
@Data
@Entity
@Accessors(chain = true)
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String status;
}
@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long> {
}
@Service
public class MyService {
public void throwsAnRuntimeException() {
throw new RuntimeException("Rollbacks not working!");
}
}
因此,当我以通常的方式(使用本地 postgresql 数据库)运行此代码时,它会按预期工作:当我在 localhost:8080 上调用查询时,响应为 500,并且我的数据库中的表完全为空,正如预期的那样,因为当方法@Transactional
以 终止时RuntimeException
,它会执行rollback
整个事务(即使最终块有repository.save()
)。但是当我尝试使用(测试范围的类路径中的 h2 数据库)
测试此代码时:@DataJpaTest
@DataJpaTest
class MyControllerTest {
@Autowired
private MyRepository repository;
@Test
void justForTest() {
var controller = new MyController(repository, new MyService());
assertThrows(RuntimeException.class, controller::justForTest);
var afterTestEntities = repository.findAll();
System.out.println(afterTestEntities.getFirst());
assertEquals(0, afterTestEntities.size());
}
}
我收到测试失败,并且调试 println 显示我的实体状态为失败MyEntity(id=1, status=FAIL)
。但我认为,就像在实际运行中一样,由于事务回滚,我应该有一个空的存储库。
所以,我的主要问题是如何@Transactional
在单元测试中测试该机制?