Drawn to this forum by the book of this week, I'd like to ask your opinions on mocking, especially when it comes to constructors and static classes.
Let me explain. I use TDD constantly during the day. That means: I make a new class, and right after creating the class, I start writing the test - what we all do, right? Considering we're using a mixture of EJB and CDI (JavaEE) for the moment, I also start mocking. Now, usually, you just mock your injected instance variables with Mockito. But when you start using API's such as the java.io API, you instantly encounter objects such as File. File has a quite straightforward though irritating API: it'll start creating filehandles and actual files on disk, which is quite annoying for unit tests (we don't want to write to disk, since that would be the target of an integration test, not a unit test). So, enter PowerMockito, which allows me to mock the constructors. And once you start doing that, going overboard is quite easy. I've actually written unit tests which were 3 times as long as the actual code, containing 15+ mocks. I mocked every class, or better yet: every constructor call. The downside was writing a lot of mocking code - the up side is that I could actually test the constructor call, without having to know the internals of the resulting object or its constructor related logic. It even kept the IOExceptions and what not away. Duly noted should be that in the beginning, I started writing "FileGenerators" and stuff like that, to generate an actual file which I could use. But I stopped doing that, since - as I said - that's the target of an integration test, not a unit test.
Same goes for the static classes. I constantly find myself mocking the static calls, since I want to control my unit, not having it rely on a static class which can do stuff I don't really care about in my unit test. Needless to say I've become quite the heavy user of PowerMockito - sometimes to grand dismay of my co-workers.
So I wanted to pose the questions to the author as well as to the forum members: what do you consider boundaries for a unit test (which is actually what this is all about)? Do you mock all constructor calls and static classes, or not? How far would you go in controlling the "environment" for your unit? Or do you rely on the constructors and statics?
Geroen Joris wrote:Needless to say I've become quite the heavy user of PowerMockito - sometimes to grand dismay of my co-workers.
Sounds like you're aware of the trade-offs you're making. That's hardly ever a bad thing!
Geroen Joris wrote:What do you consider boundaries for a unit test (which is actually what this is all about)? Do you mock all constructor calls and static classes, or not? How far would you go in controlling the "environment" for your unit? Or do you rely on the constructors and statics?
I'd like to not have more than a handful of static methods in a code base – and none that I'd want to stub in tests. (I'd also like a red Ferrari that goes a hundred miles per gallon and never breaks down.) In practice it's often a trade-off decision between how far you refactor now and how quickly you proceed with adding new functionality. Sometimes I end up refactoring away from static methods and sometimes I end up working around them. Sometimes I even skip writing a test altogether because it isn't easy enough.
You mentioned the java.io.File API as an example. When there's only a couple of classes that deal with the File class, I tend to just suck it up and write a few integration tests that operate on actual files in a temp directory. If the file system stuff is a major element of the code base I'm working with, I'd be looking for an abstraction that reduces the number of places where my code base is exposed to the File API. That's not a trivial refactoring so I don't do it that often.