Search This Blog


Wednesday, September 17, 2008

Why Every Good Developer needs to Know how to Mock

While unit testing is generally considered a good practice ( even among those who don't do unit tests), mocking doesn't seem to carry the same aura. There are a lot of arguments saying why mocking is bad , how it kills testability etc. 

But in my day-to-day job, as well as in my personal projects, I found mocking is definitely indispensable. Here are the few situations where mocking are absolutely necessary:
  1. Testing the GUI interaction
  2. Testing the web application
  3. Testing the code that interacts with hardware and/or third party library.
  4. Testing legacy application
Testing the GUI interaction

GUI is notoriously hard to test. You can use GUI test automation tools and scripting languages, but they are never as good as the pure unit testing itself. 

But with the judicious use of mocking tools, you can test the GUI logic. I wrote such an example here. Although you still need to properly segment your code ( such as do not put logic code in the event handler methods), but mocking tools can help to test the GUI logic without all the complexities that are associated with GUI test automation tools. 

Without mocks, there is no way to test the GUI interaction, simply because there is no way to override the forms controls. 

Testing the Web Application
ASP.NET MVC framework is designed for testability. All the essential classes ( such as HttpContext, HttpRequest etc) are made abstract so that you can easily override them to write mock classes for unit testing purpose. Yeah, you can do that, by using dependencies injection and sub-classing and all sorts of techniques.  

But it is not easy to do that. Because these classes are somehow interdependent and so you need to know how to properly set them up or else your mocks just won't work. It's much better to just mock the classes and run the tests. Want to simulate the http request? Just mock it and return the values you want! Why need to inherit the HttpRequestBase and fill in all the properties

The use of mocking on ASP.NET MVC is another example on why mocking doesn't hurt testability, in fact, it compliments it. Yes, your code has the proper separation of concern. Yes, all the relevant views and logic are separated. But mocking helps you to write tests faster, and cleaner, without the need to setup all the nitty-gritty ground work.

Test the code that interacts with hardware/ third party tools.
If you subscribe to the purist's dogma, there is no way for you to test the code that interacts with hardware. writing tests to access the hardware is a non-starter; because when things get messed up you don't know whether they are your problem or the hardware's problem. 

To properly test your logic, you need to assume the hardware's reaction given certain circumstances. But if you do that, you are already mocking. 

Testing Legacy Application
Ever get your hands on legacy applications that are not designed for testability? If yes, then you will definitely yearn for mocking tools.

In my life as a developer I've came across a lot of legacy applications that are simply not geared towards testability. Writing unit tests are hard, because every nontrivial method seems to do too many things and access external files and sometimes even require full setup of the application. Refactoring them into something more test friendly is a challenging exercise because well... it's a chicken-and-egg problem: You write tests to prevent you from accidentally breaking the code, but you can't write tests before you make changes. 

The use of mocking tools can somehow alleviate this problem. Your method calls a gigantic object that needs thousands of lines to setup but somehow the method only uses two properties? Then why bother to set it up before the test? Just mock it! The logic of file reading and manipulation is coupled? Then just mock the file content and test the logic!

There is no silver bullet in software development. But without mocking, I can't conceive a single way where we can apply the unit testing practices in the real world.

No comments: