JUnit 5 Timeout бесконечно долго выполняется тест

Всем привет! Пытаюсь разобраться в работе Timeout в JUnit 5. Есть два ассерта для timeout

При использовании ассерта assertTimeout, если время теста превышает 30 секунд, тест выполняется, но заканчивается с ошибкой

@Test
    void test_Call_Main_Window_Icon_Tree() {
        assertTimeout(ofSeconds(30), () ->{
            windowMain.getIconClientPanelTree().click();
            assertTrue(windowMain.isMainWindow(), "Вызов главного окна через иконку в трее не работает");
        }, () -> "Тест выполняется больше 30 секунд");
    }

А вот при таком ассерте assertTimeoutPreemptively тест выполняется бесконечно долго, хотя в документации написано, что вроде как он должен вылетать с ошибкой, если время выполнения больше заданного

@Test
    void test_Call_Main_Window_Icon_Tree() {
        assertTimeoutPreemptively(ofSeconds(30), () ->{
            windowMain.getIconClientPanelTree().click();
            assertTrue(windowMain.isMainWindow(), "Вызов главного окна через иконку в трее не работает");
        }, () -> "Тест выполняется больше 30 минут");
    }

Почему во втором случае тест не падает с ошибкой?

Ошибка появятся когда код завершит исполнение :grin:

1 лайк

Так в первом случае тест все таки выполняется. Почему во втором не выполняется?

package com.github.bratuhin.example;

import org.junit.jupiter.api.Test;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;

public class TimeTest {
  @Test
  public void infinity() {
    assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
      while (true) ;
    }, () -> "Тест выполняется больше 100 ms");
  }
}

Судя по моему тесту - все работает как надо и тест прерывается.
Если верить оф. документации могут быть проблемы с ThreadLocal:

Preemptive Timeouts

The various assertTimeoutPreemptively() methods in this class execute the provided executable or supplier in a different thread than that of the calling code. This behavior can lead to undesirable side effects if the code that is executed within the executable or supplier relies on ThreadLocal storage.

One common example of this is the transactional testing support in the Spring Framework. Specifically, Spring's testing support binds transaction state to the current thread (via a ThreadLocal) before a test method is invoked. Consequently, if an executable or supplier provided to assertTimeoutPreemptively() invokes Spring-managed components that participate in transactions, any actions taken by those components will not be rolled back with the test-managed transaction. On the contrary, such actions will be committed to the persistent store (e.g., relational database) even though the test-managed transaction is rolled back.

Similar side side effects may be encountered with other frameworks that rely on ThreadLocal storage. 

Если что, то над таймаутами в 5-м JUnit’е как раз сейчас идёт какая-то работа, точнее ещё с прошлого года что-то делают: https://github.com/junit-team/junit5/issues/80
Также были какие-то сообщения про проблемы на JDK 11, или я не так их воспринял.
У меня в практике с JUnit4 были случаи когда его таймаут тоже не отрабатывал из-за JDBC, просто база не отпускала коннект и держала сколько ей было нужно…