views:

691

answers:

3

I have a Singleton/Factory object that I'd like to write a JUnit test for. The Factory method decides which implementing class to instantiate based upon a classname in a properties file on the classpath. If no properties file is found, or the properties file does not contain the classname key, then the class will instantiate a default implementing class.

Since the factory keeps a static instance of the Singleton to use once it has been instantiated, to be able to test the "failover" logic in the Factory method I would need to run each test method in a different classloader.

Is there any way with JUnit (or with another unit testing package) to do this?

edit: here is some of the Factory code that is in use:

private static MyClass myClassImpl = instantiateMyClass();

private static MyClass instantiateMyClass() {
 MyClass newMyClass = null;
 String className = null;

 try {
  Properties props = getProperties();
  className = props.getProperty(PROPERTY_CLASSNAME_KEY);

  if (className == null) {
   log.warn("instantiateMyClass: Property [" + PROPERTY_CLASSNAME_KEY
     + "] not found in properties, using default MyClass class [" + DEFAULT_CLASSNAME + "]");
   className = DEFAULT_CLASSNAME;
  }

  Class MyClassClass = Class.forName(className);
  Object MyClassObj = MyClassClass.newInstance();
  if (MyClassObj instanceof MyClass) {
   newMyClass = (MyClass) MyClassObj;
  }
 }
 catch (...) {
  ...
 }

 return newMyClass;
}

private static Properties getProperties() throws IOException {

 Properties props = new Properties();

 InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILENAME);

 if (stream != null) {
  props.load(stream);
 }
 else {
  log.error("getProperties: could not load properties file [" + PROPERTIES_FILENAME + "] from classpath, file not found");
 }

 return props;
}
+2  A: 

When I run into these sort of situations I prefer to use what is a bit of a hack. I might instead expose a protected method such as reinitialize(), then invoke this from the test to effectively set the factory back to its initial state. This method only exists for the test cases, and I document it as such.

It is a bit of a hack, but it's a lot easier than other options and you won't need a 3rd party lib to do it (though if you prefer a cleaner solution, there probably are some kind of 3rd party tools out there you could use).

Mike Stone
+2  A: 

You can use Reflection to set myClassImpl by calling instantiateMyClass() again. Take a look at this answer to see example patterns for playing around with private methods and variables.

Cem Catikkas
+1  A: 

Singletons lead to a whole world of hurt. Avoid singletons and your code becomes much easier to test and just all-round nicer.

Tom Hawtin - tackline
Why negative, its a good suggestion. +1
Adeel Ansari