Проверка Mockito с таймаутом для синхронизированного метода не выполняется в Eclipse - PullRequest
1 голос
/ 05 августа 2020

При использовании Mockito verify с таймаутом для ожидания вызова асинхронного метода иногда происходит сбой, если метод синхронизирован.

Я наблюдал эффект с несколькими версиями Eclipse, включая 2020-06 (4.16.0) и Mockito 3.1.0 и 3.4.6. Пример ниже иллюстрирует проблему (и тест, и испытуемый находятся в одном классе для простоты). Почему это не удается?

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class A {
  @Mock
  private A a;

  public synchronized void f() {
    // Do stuff
  }

  @Test
  void test() {
    // Call a.f() asynchronously and with a small delay 
    // (to make the test thread yield).
    new Thread(() -> {
      try {
        Thread.sleep(100);
      } catch (final InterruptedException e) {
        Thread.currentThread().interrupt();
      }
      a.f();
    }).start();

    // This verification fails, but it should pass.
    Mockito.verify(a, Mockito.timeout(2000)).f();
  }
}

Примечательные моменты:

  • Эффект воспроизводится не полностью. Фактически, мои примеры из реальной жизни никогда не выходят из строя на одних компьютерах, в то время как на других они всегда терпят неудачу, что указывает на состояние гонки.
  • Удаление ключевого слова synchronized решает проблему, даже при замене его на synchronized(this) блок в теле метода.
  • Если класс, содержащий синхронизированный метод, реализует интерфейс, фиксация интерфейса вместо конкретного класса решает проблему.
  • Удаление спящего режима в приведенном выше примере, следовательно Повышение вероятности того, что вызов f завершится до вызова verify, решает проблему.
  • Поведение подозрительно похоже на проблему, описанную (и предположительно решенную) здесь: https://github.com/mockito/mockito/issues/253.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...