Java 我可以为测试目的修改字段的值吗?

Java 我可以为测试目的修改字段的值吗?,java,reflection,singleton,junit4,java-7,Java,Reflection,Singleton,Junit4,Java 7,为测试目的更改字段的值时遇到问题 尽管存在单例的问题,我还是想将其用于日志文件管理器。实际上,我考虑过是否应该重新设计,但很高兴我的决定可能还可以 不过我想测试一下。特别是如果代码是在windows和linux上运行的,或者是在我现在想不起来的其他地方 其思想是在当前目录中创建一个名为“testlogs”的测试目录,删除它并使用它。因此,我可以确保我至少在当前目录中具有写入权限,或者我可以通知用户不会写入日志文件,或者我可以提示用户选择其他位置等 在下面的代码中,我不断获取我的“logs”目录。

为测试目的更改字段的值时遇到问题

尽管存在单例的问题,我还是想将其用于日志文件管理器。实际上,我考虑过是否应该重新设计,但很高兴我的决定可能还可以

不过我想测试一下。特别是如果代码是在windows和linux上运行的,或者是在我现在想不起来的其他地方

其思想是在当前目录中创建一个名为“testlogs”的测试目录,删除它并使用它。因此,我可以确保我至少在当前目录中具有写入权限,或者我可以通知用户不会写入日志文件,或者我可以提示用户选择其他位置等

在下面的代码中,我不断获取我的“logs”目录。我希望能够节省真正的“日志”(如果存在)

为什么我不能更改
dirname
的值

package com.home.app.logger.LogsMngr;
public class LogsMngr {
    private static class Holder {
        public static String dirname = "logs";
        public static final LogsMngr INSTANCE = new LogsMngr(dirname);
    }

    private LogsMngr(String dirname){
         createDirectory(dirname);
    }

    private createDirectory(String dirname) {
         // logic to create a directory on the filesystem
    }

    public static LogsMngr getInstance() {
        return Holder.INSTANCE;
    }
}


@RunWith(SeparateClassLoaderRunner.class)
public class Test {

    LogsMngr lmngr;

    @Test
    public void test() {
        try {
            // Remove existing directory
            TUtils.rmfDirectory("testlogs");

            // Set directory name
            String className = "com.home.app.logger.LogsMngr$Holder";
            Class[] memberClasses = LogsMngr.class.getDeclaredClasses();

            Field dirnamefield = null;

            for(int i=0; i<memberClasses.length; i++) {

                if(memberClasses[i].getName().equals(className)) {

                    dirnamefield = memberClasses[i].getField("dirname");
                }
            }
            //TODO catch NullPointerException because of dirname?

            // To prevent from IllegalAccessException:
            dirnamefield.setAccessible(true);

            // Set test directory
            dirnamefield.set(null, "testlogs");

            // Create
            lmngr = LogsMngr.getInstance();
        }
        catch(Exception e) {

            e.printStackTrace();
        }
    }
}
package com.home.app.logger.LogsMngr;
公共类日志{
私有静态类持有者{
公共静态字符串dirname=“logs”;
public static final LogsMngr INSTANCE=new LogsMngr(dirname);
}
私有LogsMngr(字符串dirname){
createDirectory(dirname);
}
私有createDirectory(字符串目录名){
//在文件系统上创建目录的逻辑
}
公共静态日志NGR getInstance(){
返回持有者实例;
}
}
@RunWith(separatedClassLoaderRunner.class)
公开课考试{
LogsMngr lmngr;
@试验
公开无效测试(){
试一试{
//删除现有目录
TUtils.rmf董事会(“测试日志”);
//设置目录名
String className=“com.home.app.logger.LogsMngr$Holder”;
Class[]memberClasses=LogsMngr.Class.getDeclaredClasses();
字段dirnamefield=null;
对于(int i=0;i这一行:

Class[] memberClasses = LogsMngr.class.getDeclaredClasses();
将导致
LogsMngr.Holder
被初始化,导致
实例
字段也被初始化,因此在此之后随时更改
dirname
将无效


要完成您试图完成的任务,您必须能够在不初始化包含它的类的情况下设置
dirname
字段,我认为这在Java中是不可能的,尽管我有兴趣在这一点上进行更正。但是,我相信您可以通过简单地移动
dirname
来获得想要的效果从
Holder
进入
LogsMngr
。然后只需将
LogsMngr.dirname
设置为您想要的任何值,然后再使用
LogsMngr.Holder
进行任何操作。

为什么静态字段在初始化后不可更改,它没有标记为
final
?它可以更改,但您的单例是在initializat上创建的离子,所以之后的任何变化都不会有任何影响。
Class[] memberClasses = LogsMngr.class.getDeclaredClasses();