I'm trying to unit test a class that references static data from another class. I cannot "not" use this static class, but obviously running multiple tests has become problematic. So my question is this. Is there a way in a junit test to reinitialize a static class? That way one test is not effected by a previous test?
So in other words some way of doing this:
Foo.setBar("Hello");
// Somehow reinitialize Foo
String bar = Foo.getBar(); // Gets default value of bar rather than "Hello"
Unfortunately, I cannot change Foo, so I'm stuck using it.
Edit It appears I made my example a bit too simple. In the real code "Bar" is set by a system property and gets set to an internal static variable. So once it starts running, I can't change it.
Declaring variables only as static can lead to change in their values by one or more instances of a class in which it is declared. Declaring them as static final will help you to create a CONSTANT. Only one copy of variable exists which can't be reinitialize.
If you declare a static variable in a class, if you haven't initialized it, just like with instance variables compiler initializes these with default values in the default constructor. Yes, you can also initialize these values using the constructor.
In Java, non-static final variables can be assigned a value either in constructor or with the declaration. But, static final variables cannot be assigned value in constructor; they must be assigned a value with their declaration.
Though it was a bit dirty, I resolved this by using reflections. Rather than rerunning the static initializer (which would be nice), I took the fragile approach and created a utility that would set the fields back to known values. Here's a sample on how I would set a static field.
final Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
Here is a little example where a utility class using static initializer is re-loaded to test initialization of that utility. The utility uses a system property to initialize a static final value. Normally this value cannot be changed at runtime. So the jUnit-test reloads the class to re run the static initializer…
The utility:
public class Util {
private static final String VALUE;
static {
String value = System.getProperty("value");
if (value != null) {
VALUE = value;
} else {
VALUE = "default";
}
}
public static String getValue() {
return VALUE;
}
}
The jUnit-test:
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Test;
public class UtilTest {
private class MyClassLoader extends ClassLoader {
public Class<?> load() throws IOException {
InputStream is = MyClassLoader.class.getResourceAsStream("/Util.class");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = -1;
while ((b = is.read()) > -1) {
baos.write(b);
}
return super.defineClass("Util", baos.toByteArray(), 0, baos.size());
}
}
@Test
public void testGetValue() {
assertEquals("default", getValue());
System.setProperty("value", "abc");
assertEquals("abc", getValue());
}
private String getValue() {
try {
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> clazz = myClassLoader.load();
Method method = clazz.getMethod("getValue");
Object result = method.invoke(clazz);
return (String) result;
} catch (IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new IllegalStateException("Error at 'getValue': " + e.getLocalizedMessage(), e);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With