Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Eclipse中同步方法超时的Mockito验证失败_Java_Eclipse_Mockito_Synchronized - Fatal编程技术网

Java Eclipse中同步方法超时的Mockito验证失败

Java Eclipse中同步方法超时的Mockito验证失败,java,eclipse,mockito,synchronized,Java,Eclipse,Mockito,Synchronized,当使用Mockitoverify并超时等待异步方法调用时,如果方法被同步,则有时会失败 我在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
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)
    块也是如此
  • 如果包含synchronized方法的类实现了一个接口,那么模拟该接口而不是具体的类可以解决这个问题
  • 在上面的示例中,删除睡眠,从而增加了在调用
    verify
    之前完成对
    f
    的调用的可能性,从而解决了问题
  • 该行为可疑地类似于此处描述(并可能已解决)的问题:

“它有时会失败……调用真正的实现”。Mockito有时还是总是调用真正的实现?不幸的是,这很难说。在我的机器上(问题总是发生在那里),调试器总是逐步进入真正的实现。但是,有些机器通过了测试(至少是我的真实测试)。这意味着已按预期调用mock方法。因为我根本无法让它在我的机器上工作,所以我无法调试这种情况。登录real方法可能会有所帮助?好的,在使用上面的最小示例重试后,我发现它的行为与我的实际示例不同,因为它在不调用real方法的情况下失败。这就回答了问题。作为记录:在调试此类问题时减少变量的数量。例如:在没有IDE的情况下完成它。只需命令行、javac、java二进制文件、文本编辑器(如果“eclipse”与这个问题有任何关系,我会非常惊讶)。记录在案:尝试编写避免原始线程的代码。使用执行者代替。。。因为这为在测试环境中使用“单线程执行器”打开了大门。这意味着:您可以测试整个代码,但可以在单个线程中运行它。通常情况下:足够好,但具有确定性。“它有时会失败……称之为真正的实现”。Mockito有时还是总是调用真正的实现?不幸的是,这很难说。在我的机器上(问题总是发生在那里),调试器总是逐步进入真正的实现。但是,有些机器通过了测试(至少是我的真实测试)。这意味着已按预期调用mock方法。因为我根本无法让它在我的机器上工作,所以我无法调试这种情况。登录real方法可能会有所帮助?好的,在使用上面的最小示例重试后,我发现它的行为与我的实际示例不同,因为它在不调用real方法的情况下失败。这就回答了问题。作为记录:在调试此类问题时减少变量的数量。例如:在没有IDE的情况下完成它。只需命令行、javac、java二进制文件、文本编辑器(如果“eclipse”与这个问题有任何关系,我会非常惊讶)。记录在案:尝试编写避免原始线程的代码。使用执行者代替。。。因为这为在测试环境中使用“单线程执行器”打开了大门。这意味着:您可以测试整个代码,但可以在单个线程中运行它。通常情况下:足够好,但具有确定性。