by Miško Hevery
Recently many of you, after reading Guide to Testability, wrote to telling me there is nothing wrong with static methods. After all what can be easier to test than Math.abs()! And Math.abs() is static method! If abs() was on instance method, one would have to instantiate the object first, and that may prove to be a problem. (See how to think about the new operator, and class does real work)
The basic issue with static methods is they are procedural code. I have no idea how to unit-test procedural code. Unit-testing assumes that I can instantiate a piece of my application in isolation. During the instantiation I wire the dependencies with mocks/friendlies which replace the real dependencies. With procedural programing there is nothing to “wire” since there are no objects, the code and data are separate.
Here is another way of thinking about it. Unit-testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. seams work through polymorphism, we override/implement class/interface and than wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to overrider the called method dependency.
Lets do a mental exercise. Suppose your application has nothing but static methods. (Yes, code like that is possible to write, it is called procedural programming.) Now imagine the call graph of that application. If you try to execute a leaf method, you will have no issue setting up its state, and asserting all of the corner cases. The reason is that a leaf method makes no further calls. As you move further away from the leaves and closer to the root main() method it will be harder and harder to set up the state in your test and harder to assert things. Many things will become impossible to assert. Your tests will get progressively larger. Once you reach the main() method you no longer have a unit-test (as your unit is the whole application) you now have a scenario test. Imagine that the application you are trying to test is a word processor. There is not much you can assert from the main method.
We have already covered that global state is bad and how it makes your application hard to understand. If your application has no global state than all of the input for your static method must come from its arguments. Chances are very good that you can move the method as an instance method to one of the method’s arguments. (As in method(a,b) becomes a.method(b).) Once you move it you realized that that is where the method should have been to begin with. The use of static methods becomes even worse problem when the static methods start accessing the global state of the application. What about methods which take no arguments? Well, either methodX() returns a constant in which case there is nothing to test; it accesses global state, which is bad; or it is a factory.
Sometimes a static methods is a factory for other objects. This further exuberates the testing problem. In tests we rely on the fact that we can wire objects differently replacing important dependencies with mocks. Once a new operator is called we can not override the method with a sub-class. A caller of such a static factory is permanently bound to the concrete classes which the static factory method produced. In other words the damage of the static method is far beyond the static method itself. Butting object graph wiring and construction code into static method is extra bad, since object graph wiring is how we isolate things for testing.
“So leaf methods are ok to be static but other methods should not be?” I like to go a step further and simply say, static methods are not OK. The issue is that a methods starts off being a leaf and over time more and more code is added to them and they lose their positions as a leafs. It is way to easy to turn a leaf method into none-leaf method, the other way around is not so easy. Therefore a static leaf method is a slippery slope which is waiting to grow and become a problem. Static methods are procedural! In OO language stick to OO. And as far as Math.abs(-5) goes, I think Java got it wrong. I really want to write -5.abs(). Ruby got that one right.
55 responses so far ↓
Amen to -5.abs(). I’m not sure, after java 1.5 autoboxing, why they couldn’t just do that? Add the mechanism to Number, along with all sorts of math that seems to work just fine on BigDecimal and BigInteger. <sigh>Anyway, my personal phrasing has been static is OK if it’s stateless, period. But I hadn’t considered the very real point of initially stateless things starting to accumulate state as they’re used in different contexts. That’s important, especially as people start using Agile methods which end up requiring incremental design and architecture. My big flag that I wave around, architecturally, is “don’t paint yourself into a corner”. I can see how static methods would potentially do that.BTW, an argument I got into with a client was that they had used an alternative to jUnit and TestNG which allowed them to manipulate bytecode in order to test statics, and inject dependencies into static stuff. It seemed like a pretty typical tool-based workaround to bad design, but I couldn’t make the point.
Argh. This comment editor kills my line breaks.
Thanks for writing more about this. It’s really helping me understand more about writing good, testable code and OOP principles.
Hi, I really enjoyed reading your blog, and I keep forwarding your entries halfway around the world. With this one I don’t completely agree however. Don’t get me wrong, I do agree with all your arguments, it’s just that static methods (in the OO sense of the word) are not necessarily procedural, functional programs are often built solely on ‘static methods’ and they are quite possible to execute in isolation, that’s pretty much a big part of functional programming. If a static method contains no references (i.e. dependencies) to other methods, which is often the case in functional programming (the functions being called are passed as parameters, cf. ‘map’ in most functional languages), it’s quite testable. This appears to be the case with Math.abs, wouldn’t you agree? Of course, there’s no way to be absolutely sure…
so what about static factory methods? the ones you find in Google Collections like Lists.newArrayList(), or ObjectMother’s to give you entity instances for tests? are really that bad? ;Pbtw, very nice article!
Named constructors are OK. Lists.newArrayList() is equivalent to new ArrayList() (if you inline the code). So really it is just a better named constructor. The issue becomes when you have WebServer.create(); There is more than a single object being created there with a lot of configuration.
Do you feel this also applies to dynamic languages? You can over come a lot these issues with monkey patching an object, aside from static methods accessing global state as any global state is obviously bad. Also, I would an application consisting solely of static methods sounds flat out scary.
I really like your blog, but I can’t disagree more with this article.First of all, they aren’t “static methods”, that’s just Sun Speak. They are functions or procedures. That they are attached to classes is an annoyance in the construction of Java, and part of the reason I avoid that language.What you are really saying is “use objects and methods, don’t use functions” whereas really it makes sense to use both paradigms depending on the situation.Second, if a function has global state (in that case it’s really just a procedure) or is tightly coupled to something it shouldn’t be, that is a flaw in the design of the function. You can make the same poor design choices writing a class, as you’ve discussed many times on your blog.You may need polymorphism to properly implement decoupling… but you don’t need objects for polymorphism . In Java you do, but most languages offer first class functions or in C++’s case, templates, to implement polymorphism.Third, it is poor design to make a function a member of a class if it isn’t involved in protecting the invariants of the class. You should not have to modify nor inherit from a class in order to extend its functionality. Modification requires source and unnecessarily increases the classes complexity, and implementation inheritance suffers from the fragile base class problem.It’s an application of the open close principle, make the class open to extension and closed to modification.Technically, this isn’t “OO” as defined by Sun’s marketing department, but who cares? It’s a better design. A design that comes from combining the functional and OO paradigms.
Hi,I really hope that you are aware that static method can be isolated and mocked using the proper tool set.(on the Java side you might wish to take a look into JMockit and PowerMock)Some modern mocking frameworks are not based on inheritance and polymorphism but on interception and AOP concepts. this allow them much more power and capabilities then apparently those you are talking about here.
@Lior,
Yes I am aware of them, and I think it is a bad idea. You are trying to compensate bad design with Monkey Patching.
@mikso:
Writting clean “academic” code is usually the opposite of writting efficient code (performance of exec).
Do you have a talk about the performance impact (better/worse, etc) of dependency injection removal of global states, static methods, etc.? (Developers love this kind of talk
)
Thanks for all your talks that make me realize that I still need to learn a lot!
@misko:
If we agree that static method can be tested as easily as any other kind of method, why exactly are they “a death to testability”?
This whole post is based on the false assumption that static method cant be mocked which as you know is a flase one.
Regarding static being a bad design, thats a whole different ball game, I for myself would find it very hard to completely strike off a major mechanism that appears in most programming languages.
Your post is very good and has been very helpful to me, but the comment about “-5.abs()” seems completely unrelated.Math.abs() is akin to ‘plus’ or ‘times’ in that it is a well-defined operation on a primitive int. It defines ‘absolute value’ for the Java language, and so should not be overwritable and should not be called like “-5.abs()”.
I completely agree with Brendan Miller. I would like to quote Bjarne Stroustrup where he describes a general date class that should be extended with functions:
“The function that finds the next weekday, or the next Sunday, can be put on top of it. I have seen Date classes with 60 or 70 operations, because they built everything in. Things like find_next_Sunday. Functions like that don’t logically belong in the class. If you build them in, they can touch the data. That means if you want to change the data layout, you have to review 60 functions, and make changes in 60 places.
Instead, if you build a relatively simple interface to a Date class, you might have five or ten member functions that are there because they are logically necessary, or for performance reasons. Then you get these five or ten operations, and you can build the other 50 in a supporting library. That way of thinking is fairly well accepted these days. Even in Java, you have the containers and then the supporting library of static methods.
I’ve seen the Date problem solved by having a base class Date with some operations on it and the data protected, with utility functions provided by deriving a new class and adding the utility functions. You get really messy systems like that, and there’s no reason for having the utility functions in derived classes. You want the utility functions to the side so you can combine them freely. How else do I get your utility functions and my utility functions also? The utility functions you wrote are independent from the ones I wrote, and so they should be independent in the code. If I derive from class Date, and you derive from class Date, a third person won’t be able to easily use both of our utility functions, because we have built dependencies in that didn’t need to be there.”
Now, I really appreciate your articles and I understand your point from a testing point of view! However, I believe avoiding functions can cause messy systems. I think we need to find another way around this problem. A new or better way of testing functions. Do you think that’s possible?
Robert C. Martin’s book “Clean Code” (Prentice Hall, 2008) gives some good examples and guidelines of how to use (and when not to use) static methods. Here’s a snippet:
“Math.max(double a, double b) is a good static method. It does not operate on a single instance; indeed, it would be silly to have to say new Math().max(a,b) or even a.max(b). All the data that max uses comes from its two arguments, and not from any “owning” object. More to the point, there is almost NO CHANCE that we’d want Math.max to be polymorphic.”
So, IMHO, you took a step too far when saying “static methods are not OK”. You can mock a static method if you’re given a delegate/facade to it (instead of the class calling it directly), right? Perhaps we must ask ourselves, what criterias should be fulfilled to “legally” create a static method in test driven development?
Some made comments saying that you can’t mock a function.You don’t *need* to mock a function. That’s the whole point. Functions make things easier to mock, not harder.You have a class C and a mock of it MockC, and some function f(x) that takes an interface that C and MockC implement.Since f(x) is not a member of C, it can interact with x only through it’s interface. As soon as you mock C, you can execute f(x) on the mock. Mocking C makes it unnecessary to mock f as long as f is not a member of C.On the other hand, if f(x) were a member of C, then CMock would have to reimplement f(x) as well. x in this case is the “this” pointer in most languages, and not a formal parameter.People try to accomplish a lot of the same thing with mixins.That said, Sun went pretty far to make functions awkward to use in Java by forcing you to stick them in a class. I think they were trying to make static methods act like class methods in an OO language but didn’t think it through (if they were real class methods we’d be able to mock them). Or maybe they were just copying C++’s static members?
Very interesting article, but like OO lovers, it sounds to “academic”.In my opinion, OO is still a tool not a goal end.I agree with you, static method sucks hard… sometimes.for many others reasons, you just cannot avoid them !
We had a discussion with my friend “how to test procedural code”. In the end we don’t see why it’s not possible
All you need to do is to have your procedural code avoid global state. If you do that and put all your code into nicely managed isolated functions that do work and get all they need through arguments.You can even follow the law of Demeter and not pass anything to functions that they don’t directly need. So in theory i think it’s possible to test procedural code. From practical point of view i don’t think such programs exist
I think like most of the others that I know you from your googleTechTalks, and I really enjoy them.I think the ideas of Separation of Concerns and Dependency Injection are great. But I’m working with legacy C code and I have a hard time applying them in the unit testing. Do you mean that unless we switch to an OO language we can never do unit test in the right way?BTW, I’m from China. Hope that helps you to know how popular you are now:-)
I only know how to unit test in OO. I am simply not an expert in procedural code. I do know that the techniques I use for testing, can not be applied to procedural code.
I have always felt the same way and have gotten into many intense discussions on this topic. I always felt that static methods are not good programming. Having said that, I have used them to create Singletons that are global for a JVM.
Terry – I highly recommend the book, Working Effectively with Legacy Code. I Misko would agree, though I’m not sure if he’s read it or not. His advice mirrors much of what Michael Feathers writes in this book.
you said it yourself:
” I have no idea how to unit-test procedural code.”
there lies the problem. I recommend picking up Michael Feather’s book “Working with Legacy Code” and you’ll learn how to test static methods and singletons etc etc.
Do i disagree that they are bad? no. They definitely are bad and more difficult to test.
Stupid evil cancerous liars, I hate you! « Luke Halliwell’s Weblog // Apr 23, 2009 at 4:51 am
[...] example, I love some of Miško Hevery’s writing on the testability implications, but he gets pretty confused when he starts talking about how static functions are bad in themselves and forgets entirely about [...]
The Problem With Active Record // May 5, 2009 at 11:04 pm
[...] Some would say using Static methods simply amounts to procedural programming, and therefore is poor Object Oriented design. Others would say static methods are death to testability. [...]
If classes freely call each others public static methods it is definitely bad design. But you can always have private/protected static methods within a class. In that way you ensure that no one outside the class can access it and yet ensure a way to write algorithmic code which only operates on passed parameters (and does not work on instance members).You can look at pure algorithmic code in this way: You wire everything you need in the parameters to the call to algorithm. An example,static boolean isHeightAboveAverage(int height, int age, Sex sex) { // pure algorithm which calculates this.}
@Sachin,
What you say above makes total sense and it will not hurt testability. But the issue I have is that static methods are acceptable in weird conditions which I and you understand. Than a new developer shows up and does not understand the complex nature of static methods testability and thinks stitic methods are ok. It creates a slippery slope in which he can modify it and what once was an testable static method becomes untestable. I don’t want to have to explain this to people. There is zero cost to have that private method non-static, and I don’t want to have a debate with people when there are ok times. It is much easier to say no static methods allowed since what you are loosing is so little, and what you are preventing from happening is so much. An excellent trade.
Test Driven log4j Logging Code Example at JAW Speak // Jun 21, 2009 at 6:17 pm
[...] test verifying logging statements are correct. Often logging uses statics, and as Misko has said, statics are a death to testabilty. With Guice you can easily inject loggers automatically for the class under construction. This [...]
shaun smith » Parsley: Your Favourite Herb? // Jul 12, 2009 at 8:05 am
[...] really looks promising. I have some initial concerns (the use of Static methods for example; see: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/), but need more time to play around [...]
How to think about OO // Jul 31, 2009 at 1:20 pm
[...] forced to write static methods due to limitation of the language. But that is a rare event since static methods are death to testability. What I do find, is that in most projects static methods are [...]
To the author: you can’t be serious. Free functions are probably the most unit-testable constructs there are.
(Presuming they’re side effect free – and only a lunatic would routinely write free-functions that modify global state).
@Mr Panda,
I am totally serious! The thing is that Math.abs() is easy to test and it is static, but it is also a leaf of your call graph, and should really be -5.abs() anyway. It is easy to test, but not because it is static, but because it is leaf. The farther your static method is from the leaf of the call graph the harder it will be to test. Look at main method, it is essentially impossible to test anything form it, and it is static. Static methods cannot be overridden, and there lies the problem. Just because some static methods are easy to test does not imply that all static methods are easy to test.
Learn a functional language. Then you certainly will rewrite your post.
@Heiko,
I know few functional languages, and while I am nowhere as versed in them nor have as much experience in OO, I do know, that many things are still the same. Instead of injecting classes you need to inject functions, and testability is still something you need to think about.
But these blog posts are not about functional languages! These blog posts are about OO languages.
– Misko
Principles, Patterns, and Practices of Mediocre Programming : Steve Smith's Blog // Oct 8, 2009 at 11:44 am
[...] Static Methods are Death to Testability [...]
Se hace camino al andar… » Blog Archive » Métodos estáticos y pruebas unitarias // Dec 13, 2009 at 3:54 pm
[...] para obtener información de contexto y, sobre todo, de la plataforma. Y me viene al pelo el reciente artículo de Misko Hevery donde explica por qué los métodos estáticos son tan malos para las pruebas y delatan diseños [...]
Helltime for January 1 « I Built His Cage // Jan 1, 2010 at 6:34 pm
[...] The gist of the post is to use static members whenever you can for values that you know won’t change. There is a potentially significant performance boost, but I fear advice like this will lead monkeys to apply staticity to areas where it is inappropriate and doom their testing efforts. [...]
The performance of using static vs instance method/variables is next to insignificant, so I would not use that as an argument.
Hi,
with regards to this and also the article about Singletons, it seems to me that you are talking in general about code that has dependecy pull. e.g.
a Class X has a process() method that goes like {
y = new YImpl();
y.doIt();
}
So you have a problem with testing this method since calling process() is always calling YImpl, and this cannot be changed with some other implementation. So YImpl should have been explicitly passed to process() ?
But as we pass more and more parameters, does it not break encapsulation ? There could be problems related with improper use. So somebody may be able to pass an incorrect instance of creditcardprocessor that bypasses logging/auth ?
Hi Monoj,
My understanding of encapsulation is that only the object methods should interact with the state of the object. This is why a service object which has getters/setters breaks encapsulation. With regard to constructor I don’t think it break encapsulation, as you are not allowed to modify the state of the object, you only need to provide the state/dependencies on creation. In addition the callee is does not know how to create the dependency, it asks for it likewise.
Here is some more discussion I found online
http://stackoverflow.com/questions/1005473/must-dependency-injection-come-at-the-expense-of-encapsulation
Extension Methods are wonderful for customising your c# dev practices. So long as you don’t mind wrapping your literal numbers in brackets, why not just use something like the following?
(-5).Abs()
public static int Abs(this int someNumber)
{
return Math.Abs(someNumber);
}
Agreed with the following points in your blog:
1) Its procedural code
2) Nothing to wire
3) They have access to the global state of the application
4) It cannot be mocked.
However, please note that these points serve as “donts” while coding a static method.
1) Its procedural code : Not all the code always belong to some or the other class.
2) Nothing to wire: If you have something to wire inside the static method, it means that its high time that you revisit the implementation of this static method.
3) They have access to the global state of the application: High time again to revisit and redefine your static method
4) It cannot be mocked: If static method has to be mocked, its high time again to revisit and redefine your static method.
Purpose of static methods is to write more of utility kind of methods that takes an input, returns an output provided that it doesn’t remember the state and doesn’t depend on any external components. If you break these rules, that’s a coding problem and not to blame static methods for the same.
Static methods that puts testability at risks means that static methods were not written they were supposed to be.
That’s also the case for instance (non-static) methods as well. If one is not aware of how to write non-static methods properly, then too it can put testability at risk.
Static Methods: Time to Hit Rock Bottom | DaedTech // Nov 1, 2011 at 9:54 am
[...] They kill testability of code bases. Misko Hevery agrees. [...]
http://code.google.com/p/powermock/
Static functions are only problematic if they have unseen dependencies (violate dependency injection principles) and are not idempotent (have state). It’s not even about being leaf methods, that’s just a recursive problem of my first sentence. Static methods are just functions. Functions are extremely easy to test if they’re idempotent. That’s the functional principle. Functions may call other functions as much as they like and it doesn’t change anything about their being idempotent, as long as the functions they call are also idempotent. You can have a long chain of function calls hanging off of your static method, if none of them have any state there’s no problem. That’s why Math.abs() is easy to test, because it adheres to these principles. In the background it may make a thousand calls to hundreds of different functions, you don’t need to care.
So your rant against static methods is really a straw man rant against non-idempotent global functions, hence global state. It has nothing to do with being static. Static functions are fine and useful in OOP.
David Zentgraf is quite correct. The issue is not with a function being static or not, it is with it altering state outside its proper scope, usually in their case by storing data in static fields that does not belong there. This is easily avoided by making parameters immutable if need be. A well defined pure static function is perfectly testable – if you put in x and y, you should get z every time.
OOP programming can often show the same problem with objects which are scoped too large – the ever popular SomethingManager classes, which try to maintain the state of large portions of applications. Just as in a static method using global data, you quickly have a situation where the object is now untestable as recreating a call resulting in an error requires emulating the majority of the application state.
Static methods in Class « xiangcaohello // Apr 15, 2012 at 10:13 pm
[...] An article worthy of reading: Static Methods are Death to Testability [...]
“I have no idea how to unit-test procedural code”
Each ‘unit’ is a function. You supply input to the function via parameters and then you check the output .
Don’t forget your fundamentals: it’s all about I/O.
Statics and unit testing « Steve-Driven Development // Aug 23, 2012 at 11:56 pm
[...] was reading http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/ by Miško Hevery. He makes some excellent points about using statics and the effect they have on [...]
There seems to be a common misreading of the original article, where Misko says something like ‘if you use a static in a class, that class is harder to unit test’ and people hear ‘statics are hard to unit test’.
It’s the classes ‘infected’ by statics that are hard to test, not the static itself;
http://stevedrivendevelopment.com/2012/08/24/statics-and-unit-testing/
Here’s my take on the matter put into an article, a more moderate view than this article: http://kunststube.net/static/
Static Methods are Death to Testability « icgdevelopment // Dec 7, 2012 at 1:34 pm
[...] Static Methods are Death to Testability [...]
You’re completely right but you could also create a rule that says, ‘never call to static methods in instance methods.’ It’s just another straw man and for many of us not a good enough reason to throw away a useful language construct (ie static methods) for a particular methodology (ie TDD).
The real question should be, “why are the testing frameworks insufficient to support the language’s full feature set?” or, “what ‘safe’ practices could be used to mitigate problems introduced by calling static methods?”
One simple practice would be to enforce exception handling on static methods. Works exactly the same way as casting types does. Write it assuming that it will always throw an exception, unless it succeeds.
It’s no more difficult to track a StaticMethodException after a failed unit test than a TypeException.
Too many people parroting TDD methodology as canon and not enough questioning its shortcomings.
This series of articles is a job well done: a great discussion of principles, which is always thought-provoking. However, like other commenters I find the conclusion here overly dogmatic and stretched too far. For example what new developers might do on their own (whatever they like, obviously) is an issue of team processes and not something that merely looking at existing code magically imbues to the mental state of the new developer.
Really, it doesn’t seem that complicated. Methods call methods in other parts of your program, in libraries, and in frameworks. That’s how computer programs work. Whether a given method has access to another via something injected or via static call is not the main concern. These can all be called dependencies. What matters is whether any dependency will realistically and pragmatically need to be mocked for testing purposes. Clearly we aren’t going to mock framework calls, and I submit that mocking something like Math.Abs() will virtually always be a waste of project time.
Software engineering is an extremely complex optimization problem, and dogmatically adhering to a particular methodological religion will not be optimal. Everything has a tradeoff in complexity and impacts the bottom line, and it’s our job as professionals to keep that bottom line goal in mind and exercise judgment for each unique scenario at every scale. The principles discussed in these articles are excellent and an important part of that process, but the complexity of the process defies complete description by simple, inflexible rules. Religion belongs in church, not engineering.
I would argue that, with mocks, you should be able to test static methods with relative ease. If a static method does have a dependency to another static method, the mocked dependencies should flow over to these methods, so unless the application is using global state (which also should be mockable, in any case), it should be relatively facile.
Leave a Comment