首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >PowerMock:模拟私有静态最终变量,一个具体的例子

PowerMock:模拟私有静态最终变量,一个具体的例子
EN

Stack Overflow用户
提问于 2014-04-19 05:17:39
回答 1查看 34.7K关注 0票数 25

要通过此测试,必须执行的绝对最小模拟是什么?

代码:

代码语言:javascript
复制
class PrivateStaticFinal {
    private static final Integer variable = 0;
    public static Integer method() { return variable + 1; }
}

测试:

代码语言:javascript
复制
@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivateStaticFinal.class)
class PrivateStaticFinalTest {
    @Test
    public void testMethod() {
        //TODO PrivateStaticFinal.variable = 100
        assertEquals(PrivateStaticFinal.method(), 101);
    }
}

相关:Mock private static final variables in the testing class (无明确答案)

EN

回答 1

Stack Overflow用户

发布于 2014-04-21 23:23:24

免责声明:在各种不同的帖子上找了很久之后,我找到了答案。这是可以做到的,但普遍的共识是它不是很安全,但考虑到您只在单元测试中这样做,我认为您接受这些风险:)

答案不是嘲笑,因为大多数嘲笑不允许你进入决赛。答案有点“老生常谈”,当Java调用的是核心java.lang.reflect.Fieldjava.lang.reflect.Modifier类(反射)时,您实际上是在修改私有字段。看着this answer,我能够拼凑出你测试的其余部分,而不需要模拟来解决你的问题。

这个答案的问题在于,我在尝试修改variable时遇到了NoSuchFieldException。有关如何访问私有字段而不是公共字段,another post提供了帮助。

解释反射/字段操作:

因为Mocking不能处理final,所以我们最终要做的是深入到字段本身的根中。当我们使用Field操作(反射)时,我们在寻找类/对象内部的特定变量。一旦Java找到它,我们就得到它的“修饰符”,它告诉变量它有什么约束/规则,比如finalstaticprivatepublic等等。我们找到正确的变量,然后告诉代码它是可访问的,这允许我们改变这些修饰符。一旦我们改变了根部的“访问”以允许我们操作它,我们就关闭了它的“最终”部分。然后,我们可以更改该值并将其设置为所需的任何值。

简单地说,我们正在修改变量以允许我们更改其属性,删除final的属性,然后更改值,因为它不再是final。有关这方面的详细信息,请访问check out the post where the idea came from

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

代码语言:javascript
复制
// 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); 

将所有这些整合到一个新的超级答案中。

代码语言:javascript
复制
@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);
    }
}

更新上面的解决方案只适用于那些在静态block.When声明和初始化常量的同时初始化的常量,编译器可能会内联它,此时对原始值的任何更改都会被忽略。

票数 40
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23162520

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档