【问题标题】:Ignoring invoking internal static call忽略调用内部静态调用
【发布时间】:2016-12-07 09:39:50
【问题描述】:
public static ResponseBean call(Bean bean) throws Exception {
    // statements...
    IgnoreCall.ignoreMethodCall(bean);
    // statements...

    // return
}

使用上面的代码sn-p,是否可以测试忽略IgnoreCall.ignoreMethod(Bean)调用的方法,而不需要将整个语句置于布尔条件下?

这里是单元测试代码sn-p:

@RunWith(PowerMockRunner.class)
@PrepareTest
public ClassHelperTest {

    @Test
    public void testCall() throws Excpetion {
        // stubbing...
        ResponseBean responseBean = ClassHelper.call(bean);
        // verify/ies
        // assert/s
    }

}

注意事项:

  • 应该避免重构ClassHelper.call(Bean)。即使是糟糕的 OO 设计,重构也是昂贵的。
  • 除非另一种模式适用于替换,否则方法签名被锁定。​​
  • 尝试在目标静态方法上使用Mockito.whenPowerMockito.when,存根在运行时调试中不起作用。

【问题讨论】:

  • 事情是:static是OO设计的异常;正如您刚刚注意到的:它使您的代码更更难进行测试。 PowerMock 可以“修复”这个问题;但我宁愿建议您更改生产代码。没有静态调用,没有这样的问题。
  • 如果重构很容易,我会做到的。不幸的是,由于手头的 OO 设计很差,我被困在了这个问题上。你说的是PowerMock can fix that problem,愿意分享一下吗?
  • 感谢您的回答,但删除参数对我来说不是一个好方法。有没有可能构建模式会做?
  • 不用担心。没有在生产代码上工作,但在我做的 sn-p 上工作。回过头来看,它不适用的原因是IgnoreCall.ignoreMethodCall(Bean) 有一系列内部静态方法调用(超出本问题的范围)。
  • 我将尝试打开另一个模仿生产中的问题。我给你一个帖子。抱歉,我使用 RSS 访问 SO,所以我没有收到强制通知来奖励它,尽管赏金在我这边被扣除了。

标签: junit mockito powermock powermockito


【解决方案1】:

由于您的 cmets 表明无法更改您的生产代码,您“简单地”必须深入了解 PowerMock 的静态模拟方面;例如here 概述。

基本上你需要为静态模拟启用IgnoreCall;然后你调用 ignoreMethodCall() 一个无操作。

但正如您一直在问的那样:您的问题的核心问题是您想要模拟一个 voidstatic 方法。我在下面有一个完整的例子,但在此之前有一些解释。

重点是:你调用一个方法有两个原因:

  1. 有副作用
  2. 它返回一个值,也可能会导致副作用

void 方法只能被调用以产生副作用。问题是:当你进行 static 模拟时,它会在 class 级别上起作用。

含义:您指示 PowerMock “阻止”某个类的任何静态方法执行;您只需“消除”所有这些静态方法的副作用!因此,通过告诉 PowerMock 进行这些静态模拟,所有 void 方法都已经“消失”了。

但是如前所述,您也可以调用方法来获取它们的返回值。然后是当 Mockito 的 when() 方法启动时。你用那个方法说:当那个返回值的方法被调用时,然后做这个或那个。

长话短说;这是使用您要求的元素的 [mcve]:

package ghostcat.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

class IgnoreCall {
  public static void ignoreMethodCall(Object o) {
    System.out.println("SHOULD NOT SHOW UP: " + o);
  }
}

class CuT {
  public static Object call(Object bean) {
    System.out.println("statement1");
    IgnoreCall.ignoreMethodCall(bean);
    System.out.println("statement2");
    return "whatever";
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(IgnoreCall.class)
public class PMTest {
  @Test
  public void test() {
    PowerMockito.mockStatic(IgnoreCall.class);
    CuT.call("yeha");
  }
}

在你的例子中......有 IgnoreCall;在其中使用了一个我刚刚称为“调用”的静态方法。

这打印:

statement1
statement2

当我进去注释掉

//      PowerMockito.mockStatic(IgnoreCall.class);

打印出来:

statement1
SHOULD NOT SHOW UP: yeha
statement2

所以,一个简单的例子应该告诉你确切地你需要做什么。

我使用 eclipse neon、IBM java8 JDK,并将所有 JAR 从 powermock-mockito-junit-1.6.6.zip 导入到我的测试项目中。

【讨论】:

  • 仍然无法理解为什么存根参数不起作用?使用了Mockito.whenPowerMockito.when,两者都没有相应地工作。
  • 这应该是公认的答案。您是否阅读了@GhostCat 发布的链接? PowerMockito.mockStatic(IgnoreCall.class); 并确保您使用的是 PowerMocks 运行器。
  • @CyrilHorad 我也同意大卫所说的话。你看,你打算做的事情是在我链接到的答案中记录。那里缺少什么部分?你真的需要别人专门为你写一个例子吗?
  • 尚未接受的原因是IgnoreCall.ignoreMethodCall(Bean) 在其他类/s 上有一系列静态 void 方法调用。
猜你喜欢
  • 2020-03-06
  • 1970-01-01
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 2017-04-08
  • 2019-05-01
相关资源
最近更新 更多