当我在一个新线程中运行调用JPA存储库的代码的集成测试时,我得到的数据是在启动PostgreSQL容器期间填充的,我不能从class test(@Sql(scripts =“data.sql”)上面的脚本接收数据。
但是,当我删除测试上面的@Transactional注解时,我可以从测试和测试容器的SQL脚本中获取数据。
我的问题是,在多线程环境中,是否有可能在不删除@Transactional注解的情况下从测试脚本中获取数据?谢谢您的回答!
**应用程序堆栈:**Sping Boot 2.1v+测试容器PostgreSQL 1.10.3v+ JUnit 4.12v
数据库测试容器配置
@TestConfiguration
public class DatabaseTestConfig {
private static JdbcDatabaseContainer PSQL;
static {
PSQL = (PostgreSQLContainer) new PostgreSQLContainer("mdillon/postgis:9.4").withUsername("test")
.withPassword("test")
.withDatabaseName("test");
PSQL.start();
Arrays.asList("main_data.sql")
.forEach(DatabaseTestConfig::restoreDump);
/*
set db properties
*/
}
public void restoreDump(String fileName){
/*
insert sql data
PSQL.copyFileToContainer(fileName)...
*/
}
}
基本集成测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { DatabaseTestConfig.class, ProjectApplication.class })
@ActiveProfiles("test-int")
@AutoConfigureMockMvc
@Sql(scripts = "classpath:extra_data.sql") // insert some extra data for all integration tests
public abstract class AbstractIntTest {
@Autowired
protected MockMvc mockMvc;
在发生任何事情时调用服务的集成测试
@Transactional
public class SomeIntegrationTest extends AbstractIntTest {
@Before
public void setUp() throws IOException {
//...
}
@Test
public void callServiceTest() throws Exception {
//mockMvc.perform(post(ENDPOINT_URL)
}
具有简化逻辑的服务
@Service
@AllArgsConstructor
public class SomeService {
private final SomeJpaReporistory repo;
private final ExecutorService executor;
@Override
@Transactional
public SomeData call(){
return CompletableFuture.supplyAsync(() -> {
return repo.findAll();
}, executor).exceptionally(e -> {
throw new BadRequestException(e.getMessage());
});
}
2条答案
按热度按时间mkshixfv1#
当您将测试设为交易时,
extra_data.sql
中的SQL查询会在交易中执行。该交易会系结至特定的执行绪,并在执行测试方法之前开始,在测试方法完成之后回复:1.开始交易
1.执行
extra_data.sql
1.调用测试方法
1.回滚事务处理
在步骤3中,由于服务使用了
supplyAsync
,您将在单独的线程上调用repo.findAll()
。由于事务绑定到特定线程,因此此findAll()
调用不是执行extra_data.sql
的事务的一部分。为了能够读取由extra_data.sql
添加的数据,它必须能够读取未提交的更改并执行脏读。Postgres不支持读取未提交的隔离级别,因此这是不可能的。您需要重新审视如何用测试数据填充数据库,或者如何在测试中使用事务。也许您可以像
main_data.sql
一样将extra_data.sql
应用到数据库,以便在执行任何测试和开始任何事务之前,它始终处于适当位置。4nkexdtk2#
我是这样解决这个问题的: