maven-surefire-plugin运行单个方法,但在类上失败

时间:2018-09-28 11:38:04

标签: spring-boot junit jhipster spring-transactions maven-surefire-plugin

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

@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{

}

1 个答案:

答案 0 :(得分:0)

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

请澄清一下,默认情况下,如果您以@Transactional的身份进行测试,spring将打开一个事务,该测试将运行,并且测试完成后(无论它是通过还是失败),事务都会进行回滚,从而有效地清理数据库

现在,我在测试中看不到此消息,因此可能您没有使用此行为。 但这是纯春天,不是春天的靴子。

现在有关弹簧靴的部分。

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

如果您想“模仿”微服务的负载,则应在没有配置的情况下运行@SpringBootTest,但这超出了问题的范围。

使用冬眠测试DAO的“按书”春季启动方式是使用@DataJpaTest,该方式仅加载与数据库相关的内容,但不能与@SpringBootTest一起使用-您应该选择一个

对我来说,很明显,该测试有些棘手,而且绝对不是遵循Spring Boot约定的,因此spring / spring boot可能会反击:)

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

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

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