5 ms·
From the linked article: > Look at Stack-Overflow ... they also use only static methods for performance, we should do the same ... Gordy had dismissed Ina’s lo
by bglazer 12y ago
From the linked article:
> Look at Stack-Overflow ... they also use only static methods for performance, we should do the same ... Gordy had dismissed Ina’s love of unit testing. It’s hard to unit test code written mostly with static methods.
I also happen to like static methods quite a bit, precisely because I thought they were EASY to unit test. I thought that a static method, which is essentially just a function in the enclosing object's namespace, would be EASY to unit test. Input -> output. No state.
Am I digging my own code grave here? What am I missing?
- rverghes 12y agoHe's assuming that the static method has a dependency on something. That it's not purely functional. For example, public static doSomething() { Database.write("Did something") } Makes testing hard because Database is hardcoded.
- _asummers 12y agoAdditionally, if you need to mock that doSomething() method's behavior at all, you can't just subclass and override the method. You would need to bring in byte code voodoo (using e.g. PowerMock in Java).
- blktiger 12y agoAnd PowerMock is the bane of all existence! It can be a useful tool, but it causes all kinds of weirdness which can completely mitigate any advantages. On my current project I had to strip out most of our uses of PowerMock. While the tests pass on my local machine just fine, many of them fail for no good reason on the CI server.
- RemoteWorker 12y ago> While the tests pass on my local machine just fine, many of them fail for no good reason on the CI server. Offtopic: Time for start using Docker? :p
- blktiger 12y agoOur CI servers are already virtual machines. Or did you mean my local machine? We have a standard ecosystem that everyone uses, but there must be some difference between the CI server and our ecosystem. I simply haven't had the time to figure out what or why yet and it's better/easier to simply remove PowerMock where the tests are broken.
- RemoteWorker 12y ago> there must be some difference between the CI server and our ecosystem Well that's why I suggested using Docker: To ensure both environments are exactly the same. You say they are virtual machines, but how do you provision them? I assume you are using puppet/chef/salt/ansible and creating them from scratch, as opposed to uploading whatever image you used in dev, like you would with Docker.
- lmm 12y agoIf you can avoid it, do; PowerMock is basically only for tests that interact with badly designed code that you can't change. But sometimes you need to depend on a badly designed library, in which case having a somewhat cumbersome way to mock it is better than nothing.
- ZoFreX 12y ago"PowerMock is basically only for tests that interact with badly designed code that you can't change" Presumably where the definition of badly designed includes "uses static methods"? That's something that I hold true, and teach to other people as true, but I have started wondering about it. Whenever I ask why it's bad I get told "it makes testing hard". Well, Powermock can make testing it possible - "but powermock is only for badly designed code". What's badly designed code? And so it goes round. Is it really that conceptually bad? Or is it just that our testing tools are insufficient, or that the language itself did not make provisions for testing all of its features? I've seen a lot of code recently that uses dependency injection purely for testing, and uses builders instead of constructors all over the place, and it feels like a lot of effort and complexity to avoid using PowerMock.
- lmm 12y agoIt's not just about testing, though that's where you tend to run into it first. Statics and constructors are both second-class citizens in Java: they can't conform to interfaces, so there's no way to separate interface and implementation when using them, no way to hide information, no way to invert control or any of the other principles of good design. (Of course, Java was designed by people doing the best they could subject to particular constraints, and is now constrained by backwards compatibility. But other languages provide the same kind of features in better ways (or provide syntax that means builders and dependency injection are much less effort, depending on which way you look at it)) Pragmatically, good design is not the only concern; if you're not writing a library with binary-compatibility concerns, then IMO the syntactic overhead of builders is often a cost that outweighs the benefits. But the design costs of statics and constructors in Java are real enough, and there are very direct costs to using PowerMock (tests are harder to maintain and more brittle as they have to specify which classes they're rewriting, and it can conflict with other things that do bytecode manipulation e.g. test coverage tools).
- judk 12y agoFake, not Mock (if you need to Mock, you've alrrady lost), but yes, you shouldn't write anything static if you'll need to provide an alterate implementation of the interface.
- bglazer 12y agoSo would a better solution be to use something like: public static doSomething(Database db){ db.write("did something" }
- kevan 12y agoThat's the dependency injection[1] way to do it. [1] http://en.wikipedia.org/wiki/Dependency_injection http://en.wikipedia.org/wiki/Dependency_injection
- rverghes 12y agoNot really, because db is not static. In my example, that Database.write() method would itself be static, and thus you can't pass it in as an argument. Basically, this concept means that it's static all the way down, from the top layer to the bottom layer.
- kyllo 12y agos/static/void/
- deleted 12y ago[deleted]
- pbh101 12y agoYou put it well, and most people in this thread (including GP) seem in violent agreement. In short: static methods are easy to test, methods using static methods (whether static or not) are more difficult to test. My takeaway: the bar for moving functionality into non-static methods (which will still be decently easy to test) is quite low. If you call a static method, be prepared to own all its functionality when testing the calling method. Taken to logical conclusion, public static methods should be quite small.
- deleted 12y ago[deleted]
- praptak 12y agoHere's a round up on static methods vs testability: http://googletesting.blogspot.com/2008/12/static-methods-are-death-to-testability.html?m=1 http://googletesting.blogspot.com/2008/12/static-methods-are... Also related: http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ http://misko.hevery.com/2008/08/17/singletons-are-pathologic...
- skybrian 12y agoUnfortunately some Java developers don't distinguish between stateful and stateless static methods and just say all static methods are bad. (But note that if the method does I/O it's stateful; you generally want I/O calls to be replaceable.)
- jameshart 12y agoThe problem is that any code which calls a static method is hard to test. Because the thing that is static about static methods - the reason they are called 'static' methods - is that they are static-bound. Code which calls a static method, will be compiled with a hard, static dependency on that static method. You can't mock it, stub it, or dependency inject it. It's... static.
- ckuehne 12y agohttp://jmockit.github.io http://jmockit.github.io