【问题标题】:maven-surefire-plugin runs single method, but failed on classmaven-surefire-plugin 运行单一方法,但在课堂上失败
【发布时间】:2019-03-04 09:41:15
【问题描述】:

我编写了需要事务的测试,它看起来像:

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

}

【问题讨论】:

  • 您是否测试过 JHipster 生成的集成测试谎言 AccountResourceIntTest,它们是事务性的,所以使用 @Transactional 而不是 @EnableTransactionManagement,我不明白您为什么需要它。跨度>
  • 更新:我没有在方法名称上使用事务,但我正在尝试测试使用事务的服务。当我将 Transactional 放在方法名称上时,异常消失了,但不幸的是,我无法检查数据,因为它尚未提交。我测试的方式不对吗? ;)
  • 谢谢盖尔。请检查上面的伪代码。
  • 同时使用事务和异步很难,因为事务没有传播。通常异步测试的价值很小,因为您要测试的是同步运行时应该相同的业务逻辑。你知道你对这次测试的期望,很抱歉我帮不了你。

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


【解决方案1】:

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

澄清一下,默认情况下,如果您使用@Transactional 进行测试,spring 会打开一个事务,测试运行,当它完成时(无论它是通过还是失败),事务会有效地回滚清理数据库.

现在,我在测试中没有看到这种情况,所以您可能没有使用这种行为。 但这是纯春天,不是弹簧靴。

现在关于弹簧靴部分。

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

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

使用休眠测试 DAO 的“书本”弹簧引导方式是使用 @DataJpaTest,它仅加载与数据库相关的内容,但不能与 @SpringBootTest 一起使用 - 你应该选择一个。

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

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

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

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

【讨论】:

  • 谢谢你,你的想法让我找到了正确的答案:@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)。问题出在数据库中,@Test 方法后未清除。 github.com/jhipster/generator-jhipster/issues/6415我真的不应该在测试期间弄乱数据库,这是个好建议。
猜你喜欢
  • 2017-09-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-14
  • 2018-11-12
  • 2012-02-11
  • 2015-08-09
  • 2019-04-18
  • 2019-04-05
相关资源
最近更新 更多