Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verification with timeout on synchronized method fails #2001

Open
Peter-bytes opened this issue Aug 12, 2020 · 2 comments
Open

Verification with timeout on synchronized method fails #2001

Peter-bytes opened this issue Aug 12, 2020 · 2 comments

Comments

@Peter-bytes
Copy link

When using Mockito verify with a timeout to wait for an asynchronous method call, it sometimes fails if the method is synchronized.

I have observed the effect with multiple versions of Eclipse, including 2020-06 (4.16.0), and both Mockito 3.1.0 and 3.4.6. The example below illustrates the problem (both the test and the subject under test are in the same class for simplicity).

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();
  }
}

Noteworthy points:

  • The effect is not perfectly reproducible. In fact, my real-life examples never fail on some computers while they always fail on others, suggesting a race condition.
  • Removing the synchronized keyword solves the issue, even when replacing it with a synchronized(this) block in the method body.
  • If the class containing the synchronized method implements an interface, mocking the interface instead of the concrete class solves the issue.
  • Removing the sleep in the example above, hence increasing the chance that the call to f is finished before verify is called, solves the issue.
  • The behavior is suspiciously similar to the issue described (and presumably solved) here: Can't verify on synchronized methods of objects #253.
@spmason
Copy link

spmason commented Jan 25, 2023

Just to note that I'm seeing this bug by default in Mockito 5.0.0 - in 4.11.0 the provided test case passes but it fails in 5.0.0. I'm not able to get it to pass even without the sleep / with a longer timeout, on multiple machines. Only moving the synchronization to the body of the method works around the issue

@spmason
Copy link

spmason commented Jan 25, 2023

Just noticed this:

Mockito 5 switches the default mockmaker to mockito-inline, and now requires Java 11.

Which I guess confirms the link to #2500

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants