I'm having trouble changing the value of a field for testing purposes.
Despite the issues around singletons I want to use it for my log files manager. I actually gave it a thought if I should rework my design but was happily approved that my decision was probably OK.
I want to test it though. Especially if the code is run on windows and linux and maybe somewhere else I can't think of right now.
The idea is to create a testing directory in the current directory called "testlogs", delete it and play with it. So I can be sure I have write privileges at least in the current directory or I can inform the user that no log files will be written or I can prompt him to select another place etc.
In the following code I keep getting my "logs" directory. I would like to be able to spare the real "logs" (if they exist).
Why can't I change the value of 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();
}
}
}
References:
SeparateClassLoaderRunner.class
What's the proper way to test a class with private methods using JUnit?
Can I discover a Java class' declared inner classes using reflection?
Solution:
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();
}
}
}