使用反射更改静态最终 File.separatorChar 进行单元测试? [英] Using reflection to change static final File.separatorChar for unit testing?

查看:26
本文介绍了使用反射更改静态最终 File.separatorChar 进行单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,我正在尝试为需要使用 File.separatorChar 在 windows 和 unix 上构建路径的方法创建单元测试.代码必须在两个平台上都运行,但是当我尝试更改此静态最终字段时,JUnit 出现错误.

Specifically, I'm trying to create a unit test for a method which requires uses File.separatorChar to build paths on windows and unix. The code must run on both platforms, and yet I get errors with JUnit when I attempt to change this static final field.

有人知道发生了什么吗?

Anyone have any idea what's going on?

Field field = java.io.File.class.getDeclaredField( "separatorChar" );
field.setAccessible(true);
field.setChar(java.io.File.class,'/');

当我这样做时,我得到

IllegalAccessException: Can not set static final char field java.io.File.separatorChar to java.lang.Character

想法?

推荐答案

来自 Field.set:

如果基础字段是最终字段,则该方法将抛出 IllegalAccessException 除非 setAccessible(true) 已针对该字段成功并且该字段是非静态的.

If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this field and this field is non-static.

所以一开始你似乎不太走运,因为File.separatorCharstatic.令人惊讶的是, 有一种方法可以解决这个问题:只需通过反射使 static 字段不再是 final.

So at first it seems that you are out of luck, since File.separatorChar is static. Surprisingly, there is a way to get around this: simply make the static field no longer final through reflection.

我改编了这个解决方案 来自 javaspecialist.eu:

I adapted this solution from javaspecialist.eu:

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

我已经对其进行了测试并且可以正常工作:

I've tested it and it works:

setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"

<小时>

请务必谨慎使用此技术.撇开毁灭性的后果不谈,以下方法确实有效:


Do exercise extreme caution with this technique. Devastating consequences aside, the following actually works:

setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"

<小时>

重要更新:上述解决方案并非在所有情况下都有效.如果该字段在重置之前可访问并通过反射读取,则会引发 IllegalAccessException.它失败是因为反射 API 创建了内部 FieldAccessor 对象,这些对象被缓存和重用(参见 java.lang.reflect.Field#acquireFieldAccessor(boolean) 实现).失败的示例测试代码:


Important update: the above solution does not work in all cases. If the field is made accessible and read through Reflection before it gets reset, an IllegalAccessException is thrown. It fails because the Reflection API creates internal FieldAccessor objects which are cached and reused (see the java.lang.reflect.Field#acquireFieldAccessor(boolean) implementation). Example test code which fails:

Field f = File.class.getField("separatorChar"); f.setAccessible(true); f.get(null);
// call setFinalStatic as before: throws IllegalAccessException

这篇关于使用反射更改静态最终 File.separatorChar 进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆