maven-surefire-plugin запускает один метод, но не работает в классе - PullRequest
0 голосов
/ 28 сентября 2018

Я написал тест, требующий транзакций, он выглядит следующим образом:

@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 голосов
/ 28 сентября 2018

Я не могу комментировать на стороне JHipster, но одной из возможных причин является то, что поведение «Test Transactional» не применяется к тестовому коду.

Просто для пояснения, по умолчанию, если вы делаете тест как @Транзакционный, пружина открывает одну транзакцию, тест запускается, и когда он завершается (независимо от того, прошел он или нет), транзакция выполняет откат, эффективно очищая базу данных.

Теперь я не вижу этого втесты, поэтому, вероятно, вы не используете это поведение.Но это чистая пружина, а не пружинный башмак.

Теперь что касается пружинного чехла.

Если вы используете @SpringBootTest с конкретной конфигурацией ExchangeApp, в этом случае, шансычто он не будет загружать какие-либо автоконфигурации (например, те, которые определяют конфигурации, работающие с транзакциями, управлением источниками данных и т. д.).

Если вы хотите «имитировать» загрузку микросервиса, вам следуетзапустить @SpringBootTest без конфигураций, но это выходит за рамки вопроса.

A "by the book" способ весенней загрузки для тестирования DAO с Hibernate использует @DataJpaTest, который загружает только вещи, связанные с базой данных, но этоне может быть использован с @SpringBootTest - вы должны выбрать один.

Так что для меня ясно, что тест делает что-то хитрое и определенно не то, что следует правилам весенней загрузки, поэтому, вероятно, весенняя / весенняя загрузка наносит ответный удар:)

Теперь об асинхронных вещах.Это также может внести свой вклад в беспорядок, потому что поддержка транзакций весной сильно зависит от концепции Thread Local, поэтому, когда новый поток исполняется (в другом пуле потоков или что-то еще), информация о транзакции не распространяется, поэтому Spring не может понять, что еевсе еще в той же транзакции.Я вижу, что вы используете TransactionSynchronizationManager, но без отладки трудно сказать, что происходит.

Теперь, чтобы проверить, почему транзакция не распространяется, я думаю, что вы должны отладить приложение и посмотреть:

  • Обернуты ли службы в прокси-сервер, поддерживающий транзакции (это то, что делает @Transactional, при условии применения соответствующего BeanPostProcessor)
  • Проверьте, что на каждом шаге вы находитесь в транзакции
  • Подумайте об использовании @Transactional для теста / контрольного примера, чтобы он очистил изменения, которые были применены во время теста
...