当前位置: 首页 > 知识库问答 >
问题:

PowerMock:模拟私有静态final变量,一个具体示例

上官联
2023-03-14

要通过这个测试,必须做的绝对最小的嘲笑是什么?

代码

class PrivateStaticFinal {
    private static final Integer variable = 0;
    public static Integer method() { return variable + 1; }
}

测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivateStaticFinal.class)
class PrivateStaticFinalTest {
    @Test
    public void testMethod() {
        //TODO PrivateStaticFinal.variable = 100
        assertEquals(PrivateStaticFinal.method(), 101);
    }
}

相关:在测试类中模拟私有静态最终变量(没有明确答案)

共有1个答案

郦楷
2023-03-14

免责声明:在对各种线程进行了大量搜索之后,我找到了一个答案。这是可以做到的,但普遍的共识是,这不是很安全,但鉴于您仅在单元测试中这样做,我认为您可以接受这些风险:)

答案不是Mocking,因为大多数Mocking不允许您黑进期末考试。答案更“hacky”一点,当Java调用是corejava.lang.reflect.Fieldjava.lang.reflect.Modifier类(反射)时,您实际上是在修改私有字段。看着这个答案,我能够拼凑出您的测试的其余部分,而无需解决您的问题的嘲笑。

这个答案的问题是,我在试图修改变量时遇到了NoSuchFieldException。这方面的帮助在于另一篇关于如何访问私有而非公共领域的帖子。

反射/场操作解释:

由于Mocking无法处理最终变量,因此我们最终要做的是侵入字段本身的根。当我们使用Field操作(反射)时,我们正在寻找类/对象内部的特定变量。一旦Java找到它,我们就会得到它的“修饰符”,它告诉变量它有什么限制/规则,如最终静态私有公共等。我们找到正确的变量,然后告诉代码它是可访问的,这允许我们更改这些修饰符。一旦我们更改了根的“访问”以允许我们操作它,我们就会关闭它的“最终”部分。然后我们可以更改值并将其设置为我们需要的任何值。

简单地说,我们正在修改变量以允许更改其属性,删除final的属性,然后更改值,因为它不再是final。有关这方面的更多信息,请查看想法来源的帖子。

所以我们一步一步地传入我们想要操纵的变量,然后。。。

// Mark the field as public so we can toy with it
field.setAccessible(true);
// Get the Modifiers for the Fields
Field modifiersField = Field.class.getDeclaredField("modifiers");  
// Allow us to change the modifiers
modifiersField.setAccessible(true);
 // Remove final modifier from field by blanking out the bit that says "FINAL" in the Modifiers
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
// Set new value
field.set(null, newValue); 

将这一切结合到一个新的超级答案中。

@RunWith(PowerMockRunner.class)
@PrepareForTest()
class PrivateStaticFinalTest {
    @Test
    public void testMethod(){
      try {
        setFinalStatic(PrivateStaticFinal.class.getDeclaredField("variable"), Integer.valueOf(100));
      } 
      catch (SecurityException e) {fail();}
      catch (NoSuchFieldException e) {fail();}
      catch (Exception e) {fail();}
      assertEquals(PrivateStaticFinal.method(), Integer.valueOf(101));
    }

    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);
    }
}

更新上述解决方案仅适用于在静态块中初始化的常量。当同时声明和初始化常量时,编译器可能会将其内联,此时会忽略对原始值的任何更改。

 类似资料:
  • 我正在尝试用Groovy编写一些Spock测试,以测试一些Java代码(特别是一个servlet过滤器)。我有一些和变量想要模拟,但我无法确定是否有方法可以这样做。我知道可用于方法,对于变量有类似的东西吗? 感谢十五世。我现在可以用以下内容来设置:

  • 问题内容: 我在类中使用 私有静态最终LOGGER 字段,并且我希望 LOGGER.isInfoEnabled() 方法返回 false 。我如何通过使用Mockito或jMockit模拟静态的final字段 我的课是: 其junit为: 当我运行它的结果是: 我是jmockit的新手,我希望上述junit案例能够成功运行。而且我必须使用JMockit或Mockito,不能使用Powermocki

  • 我在我的类中使用私有静态final LOGGER字段,我希望LOGGER.isInfoEnabled()方法返回false。如何使用mockito或jMockit模拟静态final字段 我的课是: 当我运行它时,结果是: 我是jmockit新手,我希望上面的junit案例能够成功运行。我只能用JMockit或mockito,不能用powermockito。请帮帮忙。

  • 有没有可能的方法来模拟一个私人的最终场? 提前谢谢你们。

  • 我想使用Powermock(基于EasyMock)模拟私有静态内部类。这不是来自生产代码,这只是一个是否可能的问题。我很确定这是一个糟糕的设计,但这是我为科学而努力的东西。 假设我们有一个具有静态私有内部类的类: IExpectationSetters中的andReturn(capture)不能应用于(java.lang.Object)  私人静态内部阶级的嘲笑甚至可能吗?我还没有在SO上找到一个

  • 问题内容: 在Java中,两者之间有什么区别? 和 都是和,不同之处在于属性。 有什么更好的?又为什么呢? 问题答案: 通常,是指“与类型本身相关联,而不是与类型实例相关联”。 这意味着你可以在没有创建类型实例的情况下引用静态变量,并且任何引用该变量的代码都引用完全相同的数据。将其与实例变量进行比较:在这种情况下,该类的每个实例都有一个独立的变量版本。因此,例如: 打印出并且是分开的,因为x和y引