3

I want to configure certain classes (FactoryProviders) to behave differently when they are being used in unit tests.

public class ConnectionFactoryProvider {

    public static IConnectionFactory getConnectionFactory() {
        //return MockConnectionFactory if running in test mode and
        //DefaultConnectionFactory is running in production mode
    }

}

I need to return a different ConnectionFactory depending on whether the code is running in test mode (unit test) or production mode.

What is the right way to achieve this ? A few possible solutions come to mind... but is any one of them a widely followed idiom ?

  • System property through JVM args such that the value will be different when running in production and test modes.
  • Keep the fully qualified name of the factory in a properties file, and ensure that when running in test mode a different property file is available on the file system. This would be easy to do with Maven because we can control the classpath order when running in the test phase, but I am not sure if it is possible to achieve when running unit tests from within Eclipse.
  • Configure the ConnectionFactoryProvider in the tests setup method so it returns the MockConnectionFactory
Parag
  • 12,093
  • 16
  • 57
  • 75
  • Have you considered using a [mocking framework](http://stackoverflow.com/questions/22697/whats-the-best-mock-framework-for-java)? – assylias May 31 '12 at 13:01
  • assylias is right. A mocking Framework would be very helpful. – Kamau Malone May 31 '12 at 13:05
  • [Another interesting post](http://stackoverflow.com/questions/1419713/mocking-vs-faking-when-to-use-what) – assylias May 31 '12 at 13:08
  • @assylias I am using both a Mock and fake objects. I am trying to think if I can tease out the design in a small enough way so I can put the code here without it getting too complicated. – Parag May 31 '12 at 16:18

2 Answers2

5

Dependency Injection (DI). Your ConnnectionFactories are dependencies. DI will allow you to send in an instance of a ConnectionFactory as a constructor parameter. IN this way, the unit test would send in a MockConnectionFactory instance, and the live code would send in a DefaultConnectionFactory instance.

public class ConnectionFactoryProvider {
    public static IConnectionFactory getConnectionFactory(IConnectionFactory connectionFactory) {
    //use the connectionFactory
    }
}

//unit test
ConnectionFactoryProvider cfp = new ConnectionFactoryProvider(aMockConnectionFactoryInstance);

//live code
ConnectionFactoryProvider cfp = new ConnectionFactoryProvider(aDefaultConnectionFactoryInstance);

Hope that helps.

P.S. I'm a C# developer, but I think that syntax is more or less the same for you in Java.

assylias
  • 321,522
  • 82
  • 660
  • 783
Kamau Malone
  • 570
  • 1
  • 5
  • 16
1

I use the following two approaches in my code applications:

  1. Read a system property that can contain a symbolic name. In production, the default is used. The symbolic name is mapped to a config file that explains what the name means.

    That way, you can have as many config files as you want, you can add configs at runtime (no code changes necessary to enable more logging in production to trace a bug).

    Example: Name of system property is db.config. Symbolic names are h2, it, prod (default). The config files are on in ${configPath}/db-${db.config}.xml

  2. Read config based on the property user.name. That allows you to easily give each developer their own config. If there is no config file with that name, a default config is read (or the default is always read and then merged with an optional per-user config)

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Very interesting ideas. I especially found the idea of using user.name to be very interesting. Somehow I am not comfortable using that because it seems to add a lot of moving pieces in the software and making it a bit brittle. But it is full of interesting possibilities nevertheless. – Parag May 31 '12 at 16:11