我写了需要交易的测试,看起来像:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ExchangeApp.class)
@EnableTransactionManagement(proxyTargetClass = true, mode = AdviceMode.PROXY)
@ActiveProfiles({JHipsterConstants.SPRING_PROFILE_TEST})
public abstract class AbstractServiceTest {
因此,当我运行单个测试方法时:mvn test -Dtest=TestClassName#method1
可以正常工作,但是
mvn test -Dtest=TestClassName
失败,带有怪异的异常,异常表示@OneToMany中的约束违例,而BigDecimal中除法期间具有十进制计算的异常。在IDE中运行时也有相同的例外。 似乎错过了交易管理。有什么想法吗?
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FK_OPEN_EXEC_ID: PUBLIC.ORDER_PAIR_OPEN_EXEC FOREIGN KEY(EXECUTIONS_ID) REFERENCES PUBLIC.ORDER_PAIR_OPEN(ID) (2)"; SQL statement:
delete from order_pair_open where id=? [23503-197]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
UPD:我也已经尝试过
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<!-- Force alphabetical order to have a reproducible build -->
<runOrder>alphabetical</runOrder>
<parallel>classes</parallel>
<threadCountClasses>1</threadCountClasses>
<threadCountMethods>1</threadCountMethods>
<threadCountSuites>1</threadCountSuites>
</configuration>
</plugin>
UPD:它是针对我的情况的。我正在尝试使用内部的@Async
方法来测试服务,因此看来我必须在测试方法名称上标记@Transactional
才能启用事务支持,这就是为什么我尝试使用@EnableTransactionManagement(proxyTargetClass = true, mode = AdviceMode.PROXY)
的原因在类测试期间启用事务管理。这是伪代码:
class Service1Test extends AbstractServiceTest {
Service1 service1;
Repo1 repo1;
//Does not works with class call, but works with method call
//when I mark this method with @Transactional, mentioned exceptions are gone,
// but I cant check result since "registerSynchronization" were not called
@Test
public void test1() throws InterruptedException {
service1.method1();
synchronized (this) {
wait(2000l);
}
assertThat( repo1.findAll().size()).isEqualTo(1);
//repoN check
}
}
@Service
@Transactional
class Service1 {
Service2 service2;
@Async
public void method1() {
//DB operations...
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
service2.method2();
}
});
}
}
@Service
class Service2 {
Repo1 repo1;
public void method2() {
repo1.save(new Entity1());
}
}
@Service
class Service3 {
@Autowired
private ScheduledExecutorService scheduler;
public void method3() {
scheduler.schedule(() -> {
//other transactional services call
}, 1l, TimeUnit.SECONDS);
}
}
@Repository
interface Repo1 extends JpaRepository<Entity1, Long> {
}
@Entity
class Entity1{
}
答案 0 :(得分:0)
我无法在JHipster方面发表评论,但是一个可能的原因是“测试事务”行为未应用于测试代码。
请澄清一下,默认情况下,如果您以@Transactional的身份进行测试,spring将打开一个事务,该测试将运行,并且测试完成后(无论它是通过还是失败),事务都会进行回滚,从而有效地清理数据库
现在,我在测试中看不到此消息,因此可能您没有使用此行为。 但这是纯春天,不是春天的靴子。
现在有关弹簧靴的部分。
在这种情况下,如果您将@SpringBootTest
与具体配置ExchangeApp
一起使用,则可能不会加载任何自动配置-例如,那些定义用于事务的配置,数据源管理等)。
如果您想“模仿”微服务的负载,则应在没有配置的情况下运行@SpringBootTest
,但这超出了问题的范围。
使用冬眠测试DAO的“按书”春季启动方式是使用@DataJpaTest
,该方式仅加载与数据库相关的内容,但不能与@SpringBootTest
一起使用-您应该选择一个
对我来说,很明显,该测试有些棘手,而且绝对不是遵循Spring Boot约定的,因此spring / spring boot可能会反击:)
现在,关于异步的东西。这也可能导致混乱,因为spring中的事务支持在很大程度上依赖于Thread Local概念,因此当新线程(在另一个线程池或其他线程上)执行时,有关事务的信息不会传播,因此spring无法理解其事务。仍在同一笔交易中。我发现您使用了TransactionSynchronizationManager
,但没有调试它就很难知道会发生什么。
现在,为了检查交易为什么不传播,我认为您应该调试应用程序并查看:
@Transactional
就是这样做的)