【问题标题】:Using power mockito to suppress private static method使用 power mockito 抑制私有静态方法
【发布时间】:2016-09-27 09:16:49
【问题描述】:

我用我的代码做了一个小例子来说明问题

public class SiteTranslator {
   Integer id;
   //Other fields
}

public class SiteUtil {

  private static SiteTranslator siteTranslator = getSiteTranslator();

  private static SiteTranslator getSiteTranslator()
  {
    SiteTranslator siteTranslator;
    //Logic involving network call
    return siteTranslator;
  }

  private static String getEnvironment()
  {
    String env = "";
    //Logic
    return env;
  }

  public static int getParent(int siteId)
  {
    int parentId = 0;
    //Logic using siteTranslator from getSiteTranslator()
    return parentId;
  }
}


public class SiteUtilTest {
  @Test
  public void test1()
  {
    try
    {
        PowerMockito.suppress(SiteUtil.class.getMethod("getSiteTranslator")); 
        BDDMockito.given(SiteUtil.getParent(1)).willReturn(6);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
  }
}

我们从 getSiteTranslator() 方法获得的 SiteTranslator 对象被我的公共函数 getParent() 使用。由于 getSiteTranslator() 需要网络调用,因此需要对其进行抑制。但是我收到以下错误

java.lang.NoSuchMethodException: SiteUtil.getSiteTranslator()

我认为问题在于我试图模拟一个私有静态函数。但是我无法将其更改为公开。有没有办法模拟当前状态的代码。

【问题讨论】:

标签: java powermock


【解决方案1】:

事实上,您并不需要 Powermockito 来实现您所需要的。

目前,您认为您需要 Powermockito 来抑制私有静态方法,但这绝对不是要走的路。

相反,您应该重构代码以使其更易于测试:

  • 删除 static 限定符
  • 使用依赖注入

在这样的重构之后,你最终会得到类似的东西(不需要嘲笑!):

public class SiteUtil {
    private SiteTranslator siteTranslator;

    public SiteUtil(SiteTranslator siteTranslator) {
        this.siteTranslator = siteTranslator;
    }

    public int getParent(int siteId) {
        int parentId = 0;
        // Logic using siteTranslator
        return parentId;
    }

    ...
}

现在你可以这样测试了:

public class SiteUtilSpec {
    private final SiteTranslator defaultTranslator = new DummySiteTranslator();

    @Test
    public void itShouldReturnTheSixthSiteWhenWeProvideTheFirstParent() {
        SiteUtil site = new SiteUtil(defaultTranslator);

        int parentId = site.getParent(1);

        assertEquals(6, parentId);
    }
}

DummySiteTranslator 是一个假对象(也许它嵌入了一堆对测试有用的硬编码翻译),但关键是这个对象从不进行任何网络调用!使其使用安全快速(非常适合测试)。

【讨论】:

  • 我明白你在说什么,但是 siteTranslator 是用它通过网络获取的数据构建的。由于这是一项昂贵的操作,我只能在我的应用程序中执行一次(并将该数据存储在 siteTranslator 中),因此具有静态性质。每次需要调用 getParent 时,我都无法构建 SiteUtil 的新对象。
  • @PranavKapoor 我完全明白真正的SiteTranslator 实例化成本很高,而且很好。但是,如果您使用DummySiteTranslator 构建一个新的SiteUtil,那根本不是问题(不涉及SiteTranslator!)。不过,在生产代码中,您仍然只能使用真正的 SiteTranslator 构造一个 SiteUtil
  • @PranavKapoor 这就是答案。您不需要 Powermock;当你不需要它时:不要使用它。就是这么简单。
【解决方案2】:

“Spotted”的答案已经明确了,因为核心问题是:您出于绝对没有原因创建了难以测试的代码。

使用这种内部静态调用只会使您的程序难以测试;令人惊讶的是:它也使得维护、增强、重用变得困难。您需要使用 Powermock 的事实通常只是表明您的生产代码糟糕。现在您可以选择使用 PowerMock 来“修复”该问题;或者通过更改您的生产代码来真正解决问题 - 以示例代码的方式解决问题只是一种不好的做法!

所以,另一个真正的教训是:你想花一些时间来学习如何编写没有这些问题的代码;例如通过观看那些videos

【讨论】:

    猜你喜欢
    • 2015-12-13
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 2012-07-14
    • 2014-08-30
    相关资源
    最近更新 更多