maven-surefire-plugin 运行单一方法,但在 class 上失败

maven-surefire-plugin runs single method, but failed on class

我写了需要交易的测试,它看起来像:

@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

更新:我也已经试过了

 <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 测试期间启用事务管理。这是伪代码:

 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{

}

我无法在 JHipster 方面发表评论,但一个可能的原因是 "Test Transactional" 行为未应用于测试代码。

澄清一下,默认情况下,如果您作为@Transactional 进行测试,spring 打开一个事务,测试 运行s,以及它何时完成(无论它是通过还是失败) 事务执行回滚有效清理数据库。

现在,我在测试中没有看到这一点,所以您可能不会使用这种行为。 但这是纯粹的 spring,而不是 spring 引导。

现在关于 spring 启动部分。

如果您将 @SpringBootTest 与具体配置一起使用 ExchangeApp 在这种情况下,它很可能不会加载任何自动配置(例如那些定义与事务一起使用的配置,数据源管理等)。

如果你想"mimic"微服务的负载,你应该运行 @SpringBootTest不配置但它超出了问题的范围。

"by the book" spring 使用休眠测试 DAO 的启动方式使用 @DataJpaTest 仅加载与数据库相关的内容,但不能与 [=10= 一起使用] - 你应该选择一个。

所以对我来说,很明显测试做了一些棘手的事情,绝对不是遵循 spring 引导约定的事情,所以可能 spring/spring 引导反击 :)

现在,关于异步的东西。这也可能导致混乱,因为 spring 中的事务支持在很大程度上依赖于线程本地概念,因此当新线程被执行时(在另一个线程池或其他东西上),有关事务的信息不会传播,因此 spring 无法理解它仍在同一个事务中。我看到你使用了 TransactionSynchronizationManager 但没有调试很难说出会发生什么。

现在为了检查为什么交易没有传播,我认为你应该调试应用程序并查看:

  • 服务是否包装在支持事务的代理中(这就是 @Transactional 所做的,假设应用了相关的 BeanPostProcessor)
  • 检查您是否在交易的每个步骤中
  • 考虑在测试/测试用例上使用@Transactional,这样它会清除在测试期间应用的更改