3

I have a factory class to retrieve the configuration for my application:

public class ConfigurationFactory {
private static ConfigurationFactory configurationFactory = new ConfigurationFactory();

private Configuration configuration = null;

public static ConfigurationFactory getConfigurationFactory() {
        return configurationFactory;
    }

And some getConfiguration methods depending on where I am getting the config from (file, database, default, etc...):

public Configuration getConfiguration(String path){...}
public Configuration getConfiguration(String database){...}

My problem is that when I do unit test for each method, I have to restart the singleton in order to load from a different source, so the only thing I had come up to is adding this:

public void resetConfiguration() {
 this.configuration = null;
}

And I feel I'll burn in developer's hell for doing it :)

My question: Is there any other way to do it without adding this method?

Note: I have seen this and I cannot use any DI framework like Spring or Guice, management thinks adding a framework would make the project heavyweight, as this program is intended to run as a daemon on servers.

Community
  • 1
  • 1
Eugenio Cuevas
  • 10,858
  • 3
  • 29
  • 51
  • Resetting an instance is a way to go when testing singletons, because they are always hard to test and there can't be any nice way around. Sometimes this kind of problems implies that there is something that could be refactored in Your design. Would You consider refactoring? – zafarkhaja May 09 '12 at 06:59
  • Yes, but, how could I refactor it? I mean, I spent some time looking for the best way to do it, and the singleton factory seemed a good pattern, it really does the job in a clear way. Only problem I have is with the tests, but I don't want to refactor the whole thing just to fit a jUnit test... – Eugenio Cuevas May 09 '12 at 07:09
  • 1
    I see unit tests as the code quality meter. If I encounter something untestable I tend to refactor that piece of code. But, of course, this is Your code and if this testability problem doesn't bother You, resetting the instance is fine. Have You had a look at the Abstract Factory design pattern, for example? I think that should be more testable... – zafarkhaja May 09 '12 at 07:27

4 Answers4

1

Some of the things which i can think of are

  1. Use mocking frameworks like Easymock or Mockito to mock the ConfigurationFactory and use this mock objects in other calling areas.

  2. Have a setter defined in the ConfigurationFactory class and define an annotation like @TestPurpose and use this to override the singleton object from your unit tests. The annotation is to denote that this should not be used during the application flow and the function is meant only for junit purpose.

raddykrish
  • 1,866
  • 13
  • 15
  • one quick question, do you want to write unit test for ConfigurationFactory or some other class which depends on ConfigurationFactory. If some other class then definitely you can try the mocking frameworks. – raddykrish May 09 '12 at 07:10
  • No, it is just to test ConfigurationFactory. The tests are, for example, loading a config from a file, loading from database, etc.. – Eugenio Cuevas May 09 '12 at 07:13
  • Ahh..I see, then the mock's will be helpful in mocking the configs. If the constructor of this class is not doing the purpose of loading all those then you can definitely write unit tests for this class. You can return mock objects for the methods `getConfiguration` and do the asserts. – raddykrish May 09 '12 at 07:18
  • It seems that chances are using DI or this, so I'll accept it – Eugenio Cuevas May 10 '12 at 08:32
1

The first thing to fix is that your singleton should not be static. Here are a couple of articles showing you how to do that:

Once you have fixed this, you will no longer need to reset your singletons since you'll be able to inject them at will.

Cedric Beust
  • 15,480
  • 2
  • 55
  • 55
0

If you don't want to use suggested frameworks you can still just split 'src 'and 'test-src' and use a protected method instead of a public one. Thats not ideal but prevents calls of that reset-method while enabling you to test.

  • src/main/myproject.myfactory.ConfigurationFactory
  • src/test/myproject.myfactory.TestConfigurationFactory

-> in your JUnit-class use the @After or @AfterClass -methods to call reset

If you need the Factory throughout multiple test Scenarios you can also make an abstract BaseTest-class which contains an @AfterClass method to clean such Singletons.

Also you could enforce the reset by reflection in your test-code and use no extra reset-method at all but i would not recommend that.

Moddin
  • 1
0

You can use reflection, for example

public void resetSingleton() throws Exception {
   Field instance = FormatterService.class.getDeclaredField("instance");
   instance.setAccessible(true);
   instance.set(null, null);
}

See an example

Kyrylo Semenko
  • 866
  • 9
  • 11