Abby Fichtner writes The Hacker Chick Blog, co-organizes Boston's 2500 member Lean Startup Circle, and was Microsoft's Evangelist for Startups where she helped hundreds of startups as they build out the next generation of software. Her background is a mixture of developing bleeding-edge technology for startups and coaching teams on how to improve how they develop software. She's extremely passionate about building communities where innovation thrives and in helping others to push the edge on what’s possible because she believes that each & every one of us is capable of changing the world. Abby is a DZone MVB and is not an employee of DZone and has posted 27 posts at DZone. You can read more from them at their website. View Full User Profile

Your Unit Tests Should Mind Their Own Business

07.16.2008
| 9599 views |
  • submit to reddit

"Pure" Unit Tests with Mock Objects

Another big question people ask about unit testing revolves around how pure our unit tests need to be. Pure unit testing requires isolating an individual unit to validate its correctness.

So, for example, if our class interacts with external servers, we might create a stub to take the place of that server (such as a dummy server that simply listens on a port and returns the expected response). Our unit test can then validate our class using the stub rather than the real server. This enables us to validate that our class is doing its part correctly without depending on the external server acting right.

But what about if our class interacts with other classes? How do we factor them out? A popular idea is to use mock objects. Say we want to unit test our Training class, which contains a method enroll( Student ). Rather than passing it a real Student object, we could create a MockStudent object that implements the same interface as Student. We then tell MockStudent what methods we expect to be called, such as getFirstName() and getLastName(), and what to return for them.

Once we call Training.enroll( MockStudent), our mock object validates that every method we expected to be called was, indeed, called. We even have the option of requiring that these methods are called in a specific order. If any of the expected methods were not called, or if any unexpected methods were called, our test fails.

Using mock objects in place of real ones during unit testing

Well, I really like the idea of mock objects - up until that last little bit. We seem to be back to the same concern that I have with unit testing private methods, and that is who cares which methods in Student are called, much less in what order? All I care about is that the student was successfully enrolled in the training. Maybe Training.enroll() was only using the student's first and last name to set a unique ID and the developer later realized that it's a bad idea to have data in our key, so updated the method to use a GUID instead. Should the Training.enroll() unit test now break because that method is no longer calling Student.getFirstName()? I don't think so. And, again, I think we're setting up unnecessary barriers to refactoring.

So, this isn't meant as a "never use mock objects" anymore than a "never test private methods." Just a recommendation to consider your unit testing objectives and what's going to best serve them before blindly diving in to the latest cool thing you just read on some schmo's blog.

Here are some great resources if you'd like to learn more:
» The Flawed Theory behind Unit Testing (Michael Feathers)
» Testing Private Methods with JUnit and SuiteRunner (great stuff, even if you're not using these tools)
» Mocks Aren't Stubs (Martin Fowler)

--
Reposted from: The Hacker Chick Blog

Published at DZone with permission of Abby Fichtner, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Kevin Conaway replied on Sat, 2008/07/19 - 8:41am

Well said. 

 You made a nice case as to why its important to test the result of calling your class, not how your class computed that result.  That is an easy trap to fall into when testing with mock objects, especially when mocking the Servlet API

Abby Fichtner replied on Sun, 2008/07/20 - 1:17pm

Thanks for your comment, Kevin.  I must admit I'm a bit surprised that I haven't heard from anyone using mocks as to why they're the right way to go even if they do couple your tests with your implementation. 

Anyone out there using mock objects that can speak to the other side of this argument?

Kevin Conaway replied on Sun, 2008/07/20 - 1:48pm in response to: Abby Fichtner

[quote=haxrchick]

I must admit I'm a bit surprised that I haven't heard from anyone using mocks as to why they're the right way to go even if they do couple your tests with your implementation.

[/quote]

I don't know that Mocks are the right way so much as sometimes they're the only way.

Years ago when people would test their servlets or Struts actions, you had to interact with the HttpSession or HttpServletRequest at some point.  The choices were:

1.) Test nothing

2.) Refactor away your code that touches the Servlet API

3.) Mock the Servlet API

 Taking option 2 will eventually bring you back to a choice between 1 and 3.

J Szy replied on Mon, 2008/07/21 - 5:46am in response to: Abby Fichtner

[quote=haxrchick]

Thanks for your comment, Kevin. I must admit I'm a bit surprised that I haven't heard from anyone using mocks as to why they're the right way to go even if they do couple your tests with your implementation.

Anyone out there using mock objects that can speak to the other side of this argument?

[/quote] You should just verify what is important. If you supply a MockStudent, method call order is probably irrelevant, but if it's, say, a MockTransaction, you want to make sure that the transaction is committed after all data is written out and only then.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.