0

テスト目的でフィールドの値を変更するのに問題があります。

シングルトンに関する問題はありますが、ログ ファイル マネージャーに使用したいと考えています。設計をやり直す必要があるかどうか実際に考えましたが、私の決定はおそらく問題ないと喜んで承認されました.

でもテストしたい。特に、コードが Windows と Linux で実行されている場合、そしておそらく他の場所で実行されている場合は、今は考えられません。

アイデアは、現在のディレクトリに「testlogs」という名前のテスト用ディレクトリを作成し、それを削除して再生することです。したがって、少なくとも現在のディレクトリに書き込み権限があることを確認するか、ログファイルが書き込まれないことをユーザーに通知するか、別の場所を選択するように求めることができます。

次のコードでは、「ログ」ディレクトリを取得し続けます。本当の「ログ」(存在する場合)を惜しまないようにしたいと思います。

の値を変更できないのはなぜ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();
        }
    }
}

参考文献:

SeparateClassLoaderRunner.class

Java 言語ドキュメント

JUnitを使用してプライベートメソッドでクラスをテストする適切な方法は何ですか?

リフレクションを使用して、Java クラスの宣言された内部クラスを検出できますか?

ビル・ピューのソリューション

解決:

package com.home.app.logger.LogsMngr;
public class LogsMngr {
    private static String dirname = "logs"; <-- moved out of Holder

    private static class Holder {
        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");

            Field dirnamefield = LogsMngr.class.getDeclaredField("dirname");

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

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

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

            e.printStackTrace();
        }
    }
}
4

1 に答える 1

1

この行:

Class[] memberClasses = LogsMngr.class.getDeclaredClasses();

が初期化されLogsMngr.HolderINSTANCEフィールドも初期化されるため、dirnameその後いつでも変更しても効果はありません。

達成しようとしていることを行うには、最初にフィールドを含むクラスを初期化せずにフィールドを設定できる必要があります。dirnameこれはJavaでは不可能だと思いますが、その点で修正したいと思います。dirnameただし、に移動するだけでHolder、探している効果が得られると思いますLogsMngr。次に、何かLogsMngr.dirnameに使用する前に、必要な値に設定するだけですLogsMngr.Holder

于 2013-03-12T03:23:54.457 に答える