Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design issue: static class only initializes once, breaks unit testing

I have a static Configuration class responsible for data settings for my entire system. It loads certain values from the registry in its constructor, and all of its methods are based on these values. If it cannot get the values from the registry (which is possible if the application hasn't been activated yet), it throws an exception, which translates to a TypeInitializationException, which is fine by me.

I wrote unit tests using NUnit to make sure that Configuration's constructor handles all cases correctly - normal values, blank values, Null value. Each test initializes the registry using the relevant values and then calls some method inside Configuration. And here's the problem: NUnit has decided to run the Null test first. It clears the registry, initializes Configuration, throws an exception - all is well. But then, because this is a static class whose constructor just failed - it doesn't re-construct the class again for the other tests, and they all fail.

I would have a problem even without the Null test, because Configuration probably (I'm guessing) gets initialized once for all classes that use it.

My question is: Should I use reflection to re-construct the class for each test, or should I re-design this class to check the registry in a property rather than the constructor?

like image 395
user884248 Avatar asked Mar 31 '13 14:03

user884248


2 Answers

My advice is to re-design your Configuration class a bit. Because your question is theoretical in nature, with a little practical aspect (failure of unit test), I'll provide some link to back-up my ideas.

First, make Configuration an non-static class. Miško Hevery, engineer at google, has a very good speech about OO Design for Testability where he specifically touches global state as a bad design choice, specially if you want to test it.

Your configuration could accept RegistryProvider instance through constructor (I assume you heard about Dependency Injection principles). RegistryProvider responsibility would be just read values from registry and that's the only thing, that it should do. Now when you test Configuration, you will provide RegistryProvider stub (if you don't know what stubs and mocks are - google it, they are simple in nature), where you will hardcode values for specific registry entries.

Now, benefits:

  • you have good unit tests, because you don't rely on registry
  • you don't have global state (testability)
  • your tests don't depend on each other (each have separate Configuration instance)
  • your tests don't rely on environment, in which they are executed (you may not have permissions to access registry, but still you are able to test your Configuration class)

If you feel like you are not quite good at Dependency Injection, I would recommend a marvelous piece of art and engineering, provided to mortal souls by the genius of Mark Seemann, called Dependency Injection in .NET. One of the best book I've read about class design, which is oriented to .NET developers.

To make my answer more concrete :

Should I use reflection to re-construct the class for each test?

No, you should never use reflexion in your tests (only if it is no other case). Reflexion will make you tests:

  • fragile
  • hard to understand
  • hard to maintain

Use object-oriented practices with conjunction of encapsulation to achieve hiding of implementation. Then test only external behavior and don't rely on internal implementation details. This will make you tests depend only on external behavior and not on internal implementation, which can change a lot.

should I re-design this class to check the registry in a property rather than the constructor?

Designing you class as described in my answer will make you able to test your class not accessing registry at all. This is a cornerstone of unit tests - not to rely on external systems (databases, file systems, web, registry, etc... ). If you want to test if you can access registry at all - write separate integration tests, where you will write to registry and read from it.

Now I don't have enough information to tell you whether you should read registry via RegistryProvider in Configuration constructor, or lazily read registry on demand, that's a tricky question. But I definitely can say - try to avoid global state as much as you can, try to minimize dependency on implementation details in you tests (this related to OO principles as a whole) and try to tests you objects in isolation, i.e. without accessing external systems. Then you can mimic exceptional cases, for example does you class behaves as expected when registry is no available? It is really hard to re-create such scenario if you access registry directly via static members of a Configuration class.

like image 57
Ilya Ivanov Avatar answered Oct 04 '22 11:10

Ilya Ivanov


static classes / methods are notoriously hard to unit-test.
(Also notice that what you're currently doing isn't unit testing at all; it's integration testing (you're changing registry values for your tests).)

I'm afraid you'll have to choose between your class being testable and it being static.

A compromise you could make is to move the 'logical' bits (i.e validation etc.) to a different, non-static class, which will be called by the main static class.
That non-static class can be then easily tested.

like image 23
J. Ed Avatar answered Oct 04 '22 12:10

J. Ed