PowerMockito verifyStatic:验证对静态方法的JavaScript调用

f8rj6qna  于 5个月前  发布在  Java
关注(0)|答案(1)|浏览(86)

我正在通过static方法调用外部系统

MyExternalServiceAccessor.myMethod(param1, param2);

字符串
到目前为止,我的unit-testing above using PowerMockito 's verifyStatic如下所示

import static org.mockito.Matchers.eq;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
..

mockStatic(MyExternalServiceAccessor.class);

..

verifyStatic();
MyExternalService.myMethod(eq(arg1), eq(arg2));


现在我想进行上面的调用'best-effort'(best-effort 调用,带有 fire-and-forget 语义,我不关心响应);因此,我引用了here,将其 Package 在CompletableFuture.runAsync(..)中,如下所示

import java.util.concurrent.CompletableFuture;

CompletableFuture.runAsync(() -> {
    MyExternalServiceAccessor.myMethod(param1, param2);
});


但是,正如预期的那样,由于MyExternalServiceAccessor.myMethod(..)的xdc调用,单元测试已经变成了xdc,有时验证会失败,并出现以下错误

java.lang.RuntimeException: Wanted but not invoked com.company.team.service.serviceutils.MyClass.myFunctionBeingUnitTested(
    null,
    null
);
Actually, there were zero interactions with this mock.

  • 我知道Mockito支持 * 非static * 方法的 * 超时验证 *;对于static方法,是否有PowerMockito(或Mockito)等效的方法?
  • 如果没有,那么还有什么替代方案?我能巧妙地重写我的代码和测试,以保持它的可扩展性,同时仍然让单元测试每次都通过吗?
sq1bmfud

sq1bmfud1#

我 * 认为 * 我可能已经找到了一个修复方法,使用 * 在我的静态方法调用之后进行的非静态方法调用 * 作为“代理”,以暗示我们的静态方法调用也必须发生
我记录了一个错误度量,以防静态方法调用失败,如下所示

import java.util.concurrent.CompletableFuture;

CompletableFuture.runAsync(() -> {
    try {
        MyExternalServiceAccessor.myMethod(param1, param2);
    } catch (final Exception e) {
        // here metricLogger is injected into MyClass from outside so can be mocked for tests
        metricLogger.logCounter("MyExternalServiceAccessor.myMethod:failure", 1);
    }
});

字符串
在上面的代码中,

  • metricLogger.logCounter(..)调用是一个非静态调用,我们可以利用mockito的超时验证
  • 因为它发生在我们的静态MyExternalServiceAccessor.myMethod(..)调用之后,所以我们可以确定如果logCounter调用发生了,那么myMethod调用也一定发生了。
    • 尽管只有当我们对myMethod抛出异常的错误场景进行单元测试时,上述语句才为真 *

因此,对于一个错误场景,我们编写这样的测试,在验证预期的方法被调用之前等待100 ms

verify(mockMetricLogger, timeout(100).times(1)).logCounter(eq("MyExternalServiceAccessor.myMethod:failure"), eq(1));
verifyStatic();
MyExternalService.myMethod(eq(arg1), eq(arg2));


对于非错误场景,我们可以使用this thread中建议的技巧来等待并验证我们的mock被调用了“零”次,即即使在等待之后也没有被调用

verify(mockMetricLogger, timeout(100).times(0)).logCounter(eq("MyExternalServiceAccessor.myMethod:failure"), eq(1));
verifyStatic();
MyExternalService.myMethod(eq(arg1), eq(arg2));


到目前为止,我的测试一直通过,但由于(a)它们在开始时并不太麻烦,(b)我们正在处理可能间歇性出现的臭名昭著的错误,我不确定对于非错误场景,是否已经完全消除了片状问题。

  • (我当然可以完全消除这种不稳定性,例如在成功场景中发布一个计数器指标,并将其用作代理,但现在还不想这样做)*

UPDATE-1

我还不得不测试这样一种场景,在这种场景中,整个BRAC代码块从未被调用(由于上游条件表达式阻止流到达BRAC块被触发的这一点)。
为此,我按照this thread中的建议利用了Mockito.never()

verify(mockMetricLogger, timeout(100).times(0)).logCounter(eq("MyExternalServiceAccessor.myMethod:failure"), eq(1));
verifyStatic(never());
MyExternalService.myMethod(eq(arg1), eq(arg2));

相关问题