18

I've been reading that static methods, static classes, and singletons are evil when you try to implement unit testing in your project. When following the TDD paradigm, should I just forget that they ever existed and never use them again or is it ok to use them sometimes?

Mr Grok
  • 3,876
  • 5
  • 31
  • 40

4 Answers4

10

Never say never--static classes and methods have their place in your toolbox.

That said, if the class you are trying to isolate and test (subject under test or SUT) depends on a static class or method, you will be unable to write a test that isolates the SUT from that static dependency--when your test code runs it will still use the static call. Sometimes this is fine, but sometimes you want to create an isolated test that tests ONLY the logic of your SUT with no dependencies (usually via mocking or similar techniques).

In general I personally use static classes and methods relatively sparingly.

Due to the nature of how Singletons are implemented, they present a similar problem for isolating a SUT for unit testing. In addition, the GOF singleton concept is considered to be a bad practice by a certain percentage of software developers. I happen to agree with this sentiment, but there is hardly consensus on this subject. A quick search on google will probably give you a pretty good idea of the pros and cons of the GOF Singleton pattern.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
Phil Sandler
  • 27,544
  • 21
  • 86
  • 147
  • OK so, as a rule of thumb, is it correct to say that Static Classes or Singletons (if you don't consider them an anti-pattern) can be used when you need a single instance that is not required to hold state information (or at least very little state info and with judicious locking)? For example factory / helper / utility classes are good candidates for implementing as static classes? – Mr Grok Mar 30 '11 at 13:53
  • I would agree with that statement in general. In regards to testing, if the utility/factory/helper does not interfere with creating isolated test cases, then it's fine (there are many cases where it CAN interfere). Somewhat relevant question I asked some time ago: http://stackoverflow.com/questions/1296953/do-extension-methods-hide-dependencies – Phil Sandler Mar 30 '11 at 14:14
  • What about cloning a singleton and passing it into the test via dependency injection? It could even be initialized using simulated data. That would solve the side effect issue. – Evan Plaice Feb 07 '13 at 18:02
  • Can you give an example of when it would be fine to be unable to isolate the SUT from the static? How to you make that judgment? – Didier A. Jan 29 '15 at 18:29
  • Sure. Basically any core utility or calculation method. To pick the simplest possible example, imagine a static class/method that added two numbers together. – Phil Sandler Jan 29 '15 at 20:06
3
  1. Should you forget they ever existed? No.
  2. Should you make sure that their incorporation into your code is done in such a manner as that they are transparent to the functionality of a class? Yes.

To explain that last part further, instead of attempting to retrieve a value from a singleton within your code, try to initialize the value within a constructor argument. If your constructor grows too large, create a factory method for creation so that you can test your class without using the singleton. If that proves problematic or your singleton has mutable state (I'd be scared of that, but hey, that's me) then try to have it so that your singleton is as easy to incorporate into your testing as possible.

You don't want to have to create an entire configuration file just to test a method on a class which calculates the standard deviation of a block of stock quotes over a 4 hour period. That's too much work. But if your singleton is written in such a way as you can fill it with the data and have another class be responsible for reading in the configuration file and populating that data then you've made great strides forward.

In regards to static methods I'd argue that they're the most easily tested methods you could possible write based on the condition that you don't need to worry about global state. Static are equivalent to y = f(x) which seems simplistic but underlies the fact that no local state transitions can change the invariant that for a given x you will always get the same y.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • Statics are easy to test, but a method using a static is hard to isolate for testing. Effectively, you will always consider the logic of the static method as a part of the unit of the method calling the static. – Didier A. Jan 29 '15 at 18:31
2

As with any software engineering practice there is never one definitive solution to any situation. So you should never rule out static methods , static classes and singletons. The aim of TDD is to make your life easier, and you will notice that as you work more with TDD your code will be modular which means even if you are using static methods (... etc) your code will still be testable.

Rule I like to live by is : Use anything you want as long as your code is easily readable and your design is elegant. How you achieve these 2 is up to you. Heck you might as well use GOTOs if you still can deliver elegant code.

mjouni
  • 118
  • 10
-3

I've been reading that static methods... are evil when you try to implement unit testing

I've never read that. Could you provide a reference? And I would dispute it. I use and unit test static methods (functions) all the time, and without problems.


Edited

Thanks for the reference to Static Methods are Death to Testability: That article is garbage.

The basic issue with static methods is they are procedural code. I have no idea how to unit-test procedural code.

This indicates that the autor does not know much about unit testing. Of course you can unit test procedural code.

During the instantiation I wire the dependencies with mocks/friendlies which replace the real dependencies.

This is the key mistake: the idea that unit testing requires mock objects. It does not. In any case, you can pass the mock objects as arguments to the static method you are testing: dependency injection does not require a constructor. For more information, see the accepted answer of the question "Static Methods : When and when not"

if the static method calls another static method there is no way to overrider the called method dependency.

True but irrelevant. If static method A calls static method B, that is an implementation detail of method A. So you have no business trying to intercept the call to B. Just treat A as a unit.

Suppose your application has nothing but static methods

A strawman argument. Clearly in the context of modern unit testing we are talking about an OO program with only some static methods.

Community
  • 1
  • 1
Raedwald
  • 46,613
  • 43
  • 151
  • 237
  • I've come across quite a lot but here are a few examples: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/ http://www.thoughtshapes.com/Blog/?p=13 – Mr Grok Mar 30 '11 at 13:34
  • http://stackoverflow.com/questions/752758/is-using-a-lot-of-static-methods-a-bad-thing/752805#752805 is relevant good answer. – Raedwald Mar 30 '11 at 15:41
  • 2
    FYI: the "author" in question is Google's own testing guru, the creator of Angular.js, and he's previous work was at Adobe, Sun, Intel and Xerox. So, without being disrespectful, chances are he knows a lot more about unit testing then you do. – Didier A. Jan 29 '15 at 18:38
  • I would not ignore the dependencies of a class/method/whatever and say it is just implementation detail. You want to unit test, not an integration test. You use blackbox testing without knowing that your dependencies are bugfree. In your example you are always testing method B with A. So no unit testing of A is possible when ignoring the implementation detail of a dependency. – Binarian Aug 14 '15 at 05:52
  • This doesn't answer the question. It's just critiquing a blog article which does answer the question. – Omnimike Sep 22 '15 at 10:49
  • This answer confused the procedural code with pure functions(as in FP) – Siva Sankaran Mar 22 '22 at 14:31