如何使用 JUnit、EasyMock 或 PowerMock 模拟静态最终变量

Posted

技术标签:

【中文标题】如何使用 JUnit、EasyMock 或 PowerMock 模拟静态最终变量【英文标题】:How to mock a static final variable using JUnit, EasyMock or PowerMock 【发布时间】:2012-03-30 15:36:56 【问题描述】:

我想模拟一个静态最终变量以及使用 JUnit、EasyMock 或 PowerMock 模拟一个 i18n 类。我该怎么做?

【问题讨论】:

Mock private static final field using mockito or Jmockit的可能重复 【参考方案1】:

有没有像 mocking 这样的变量?我会称之为重新分配。我认为 EasyMock 或 PowerMock 不会为您提供重新分配 static final 字段的简单方法(这听起来像是一个奇怪的用例)。

如果你想这样做,你的设计可能有问题:如果你知道一个变量可能有另一个值,即使是为了测试目的,也要避免使用 static final(或更常见的全局常量)。

无论如何,您可以使用反射来实现(来自:Using reflection to change static final File.separatorChar for unit testing?):

static void setFinalStatic(Field field, Object newValue) throws Exception 
    field.setAccessible(true);

    // remove final modifier from field
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    field.set(null, newValue);

如下使用:

setFinalStatic(MyClass.class.getField("myField"), "newValue"); // For a String

拆除时不要忘记将字段重置为原始值。

【讨论】:

任何使用它的人都应该记住,java 编译器可以内联常量,因此代码实际上可能无法访问其他最终字段(应该适用于 File.separatorChar,因为内联时常量将无用)。这在this question 中有描述 如果我知道变量在单元测试期间只有另一个值,建议的方法是什么? 此解决方案不适用于最新的 JDK-11 或更高版本。由于在 JDK-11 或 + 的 vanilla 版本中不鼓励修改最终变量的值。【参考方案2】:

可以使用 PowerMock 功能的组合来完成。使用@PrepareForTest(...) 注释进行静态模拟,模拟您的字段(我使用的是Mockito.mock(...),但您可以使用等效的EasyMock 构造),然后使用WhiteBox.setInternalState(...) 方法设置您的值。请注意,即使您的变量是 private,这也将起作用。

有关扩展示例,请参阅此链接:http://codyaray.com/2012/05/mocking-static-java-util-logger-with-easymocks-powermock-extension

【讨论】:

注意 - “扩展示例的链接”是指模拟 static 字段,而不是问题中提到的 static final 字段。

以上是关于如何使用 JUnit、EasyMock 或 PowerMock 模拟静态最终变量的主要内容,如果未能解决你的问题,请参考以下文章

JUnit Easymock 意外的方法调用

easymock+junit+spring学习·

使用 Powermock 时出现 NoClassDefFoundError

JSF - JUnit FacesContext模拟测试

EasyMock:java.lang.IllegalStateException:预期 1 个匹配器,记录 2 个

EasyMock简单使用方法