55

In most of my applications, I have a singleton or static "config" object, in charge of reading various settings from disk. Almost all classes use it, for various purposes. Essentially it's just a hash table of name/value pairs. It's read-only, so I haven't been too concerned with the fact that I have so much global state. But now that I'm getting started with unit testing, it's starting to become an issue.

One problem is that you don't usually want to test with the same configuration that you run with. There are a couple of solutions to this:

  • Give the config object a setter that's ONLY used for testing, so you can pass in different settings.
  • Continue using a single config object, but change it from a singleton to an instance that you pass around everywhere it's needed. Then you can construct it once in your application, and once in your tests, with different settings.

But either way, you're still left with a second problem: almost any class can use the config object. So in a test, you need to set up the configuration for the class being tested, but also ALL of its dependencies. This can make your testing code ugly.

I'm starting to come to the conclusion that this kind of config object is a bad idea. What do you think? What are some alternatives? And how do you start refactoring an application that uses configuration everywhere?

12
  • The config gets its settings by reading a file on disk, right? So why not just have a "test.config" file that it can read?
    – Anon.
    Jan 26, 2011 at 20:13
  • That solves the first problem, but not the second.
    – JW01
    Jan 26, 2011 at 20:14
  • @JW01: Do all your tests need a markedly different configuration, then? You're going to have to set up that configuration somewhere during your test, aren't you?
    – Anon.
    Jan 26, 2011 at 20:17
  • True. But if I continue using a single pool of settings (with a different pool for testing), then all my tests end up using the same settings. And since I may want to test the behavior with different settings, this isn't ideal.
    – JW01
    Jan 26, 2011 at 20:22
  • "So in a test, you need to set up the configuration for the class being tested, but also ALL of its dependencies. This can make your testing code ugly." Have an example? I have a feeling that it's not the structure of your whole application connecting to the config class but rather the structure of the config class itself that is making things "ugly". Shouldn't setting up the configuration of a class automatically configure its dependencies?
    – AndrewKS
    Jan 26, 2011 at 20:25

9 Answers 9

43

I don't have a problem with a single config object, and can see the advantage in keeping all settings in one place.

However, using that single object everywhere will result in a high level of coupling between the config object and the classes that use it. If you need to change the config class you may have to visit every instance in which it is used and check that you haven't broken anything.

One way to deal with this is to create multiple interfaces that expose parts of the config object that are needed by different parts of the app. Rather than allowing other classes to access the config object, you pass instances of an interface to the classes that need it. That way, the parts of the app that use config depend on the smaller collection of fields in the interface rather than the whole config class. Finally, for unit testing you can create a custom class that implements the interface.

If you want to explore these ideas further, I recommend reading about SOLID principles, particularly the Interface Segregation Principle and the Dependency Inversion Principle.

8

I segregate groups of related settings with interfaces.

Something like:

public interface INotificationEmailSettings {
   public string To { get; set; }
}

public interface IMediaFileSettings {
    public string BasePath { get; set; }
}

etc.

Now, for a real environment, a single class will implement many of these interfaces. That class may pull from a DB or the app config or what have you, but often it knows how to get most of the settings.

But segregating by interface makes the actual dependencies much more explicit and fine grained, and this is an obvious improvement for testability.

But .. I don't always want to be forced to inject or provide the settings as a dependency. There's an argument that could be made that I should, for consistency or explicitness. But in real life it seems an unnecessary restriction.

So, I'll use a static class as a facade, providing easy entry from anywhere to settings, and within that static class I will service locate the implementation of the interface and get the setting.

I know service location gets a quick thumbs down from most, but let's face it, providing a dependency through a constructor is a weight, and sometimes that weight is more than I care to bear. Service Location is the solution to maintaining testability through programming to interfaces and allowing multiple implementations while still providing the convenience (in carefully measured and appropriately few situations) of a static singleton entry point.

public static class AllSettings {
    public INotificationEmailSettings NotificationEmailSettings {
        get {
            return ServiceLocator.Get<INotificationEmailSettings>();
        }
    }
}

I find this mix to be the best of all worlds.

4

Yes, as you realized, a global config object makes unit testing hard. Having a "secret" setter for unit testing is a quick hack, which although not nice, can be very useful: it enables you to start writing unit tests, so that you can refactor your code towards a better design over time.

(Obligatory reference: Working Effectively With Legacy Code. It contains this and many more invaluable tricks for unit testing legacy code.)

In my experience, the best is to have as little dependencies on global config as possible. Which is not necessarily zero though - it all depends on the circumstances. Having a few high level "organizer" classes which access the global config and pass on the actual config properties to the objects they create and use can work well, as long as the organizers do only that, e.g. do not contain much testable code themselves. This allows you to test most or all of the unit testable important functionality of the app, while still not completely disrupting the existing physical configuration schema.

This is already getting close to a genuine dependency injection solution though, like Spring for Java. If you can migrate to such a framework, fine. But in real life, and especially when dealing with a legacy app, often the slow and meticulous refactoring towards DI is the best achievable compromise.

2
  • I've really liked your approach and I wouldn't suggest that the idea of a setter should be kept "secret" or considered a "quick hack" for that matter. If you embrace the stance that unit tests are an important user/consumer/part of your application, then having test_ attributes and methods isn't such a bad thing anymore, right? I do agree that the genuine solution to the problem is to employ a DI framework, but in examples like yours, when working with legacy code, or other simple cases, not alienating test code applies cleanly. Jan 26, 2011 at 23:10
  • 1
    @kRON, these are immensely useful and practical tricks for making legacy code unit testable, and I am using them extensively as well. However, ideally the production code should not contain any features introduced solely for the purpose of testing. In the long run, this is where I am refactoring towards. Jan 27, 2011 at 8:51
2

In my experience, in the Java world, this is what Spring is meant for. It creates and manages objects (beans) based on certain properties that are set at runtime, and is otherwise transparent to your application. You can go with the test.config file that Anon. mentions or you can include some logic in the config file that Spring will handle to set properties based on some other key (e.g. hostname or environment).

As regards your second problem, you can get around that by some rearchitecture but it's not as severe as it seems. What this means in your case is that you wouldn't, for example, have a global Config object that various other classes use. You'd just configure those other classes through Spring and then have no config object because everything that needed configuration got it through Spring, so you can use those classes directly in your code.

2

This question is really about a more general issue than configuration. As soon as I read the word "singleton" I immediately thought of all the problems associated with that pattern, not least of which is poor testability.

The Singleton pattern is "considered harmful". Meaning, it's not always the wrong thing, but it usually is. If you're ever considering using a singleton pattern for anything, stop to consider:

  • Will you ever need to subclass it?
  • Will you ever need to program to an interface?
  • Do you need to run unit tests against it?
  • Will you need to modify it frequently?
  • Is your application intended to support multiple production platforms/environments?
  • Are you even a little concerned about memory usage?

If your answer is "yes" to any of these (and probably several other things I didn't think of), then you probably don't want to use a singleton. Configurations often need a great deal more flexibility than a singleton (or for that matter, any instanceless class) can provide.

If you want almost all the benefits of a singleton without any of the pain, then use a dependency injection framework like Spring or Castle or whatever is available for your environment. That way you only ever have to declare it once and the container will automatically provide an instance to whatever needs it.

0

One way I have handled this in C# is to have a singleton object that locks during instance creation and initializes all data at once for use by all client objects. If this singleton can handle key/values pairs, you could store any manner of data including complex keys for use by many different clients and client types. If you want to keep it dynamic and load new client data as needed, you could verify the existence of a client main key and, if missing, load the data for that client, appending it to the main dictionary. It is also possible that the primary config singleton could contain sets of client data where multiples of the same client type use the same data all accessed via the primary config singleton. Much of this config object organization may depend on how your config clients need to access this information and whether that information is static or dynamic. I have used both key/value configs as well as specific object APIs depending upon which was needed.

One of my config singletons can receive messages to reload from a database. In this case, I load into a second object collection and only lock the main collection in order to swap collections. This prevents blocking reads on other threads.

If loading from config files, you could have a file hierarchy. Settings in one file can specify which of the other files to load. I have used this mechanism with C# Windows services that have multiple, optional components, each with their own config settings. The file structure patterns were the same across files, but were loaded or not based on the primary file settings.

0

The class you're describing is sounding like a God object antipattern except with data instead of functions. That is a problem. You should probably have the config data read and stored in the appropriate object while only reading the data again if it is needed for some reason.

Additionally you're using a Singleton for a reason which is not appropriate. Singletons should only be used when the existence of multiple objects will create a bad state. Using a Singleton in this case is inappropriate as having more than one of a configuration reader should not cause an error state right away. If you have more than one, you're probably doing it wrong, but it's not absolutely necessary that you only have one of a configuration reader.

Finally, creating such a global state is a violation of encapsulation as you're allowing more classes than need to know access the data directly.

0

I think that if there are a lot of settings, with "clumps" of related ones, it makes sense to split those up into separate interfaces with respective implementations - then inject those interfaces where needed with DI. You gain testability, lower coupling, and SRP.

I was inspired on this matter by Joshua Flanagan of Los Techies; he wrote an article on the matter some time ago.

-1

I am having a hard time understanding what the fuzz is about. You typically pass a resource identifier to your application at startup that tells it what configuration to load. This could be a file path. The way you access your configuration data from within your application is hardly relevant.

You may want to consider having separate stores for application level configuration, machine level configuration and user level configuration. But this may not be useful for your kind of application.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.