问题
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?
回答1:
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.
回答2:
- Should you forget they ever existed? No.
- 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
.
回答3:
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.
回答4:
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.
来源:https://stackoverflow.com/questions/5486562/should-i-never-use-static-methods-and-classes-and-singletons-when-following-the