views:

478

answers:

7

During a recent interview I was asked why one would want to create mock objects. My answer went something like, "Take a database--if you're writing test code, you may not want that test hooked up live to the production database where actual operations will be performed."

Judging by response, my answer clearly was not what the interviewer was looking for. What's a better answer?

+19  A: 

I'd summarize like this:

  • Isolation - You can test only a method, independently on what it calls. Your test becomes a real unit test (most important IMHO)
  • Decrease test development time - it is usually faster to use a mock then to create a whole class just for help you test
  • It lets you test even when you don't have implemented all dependencies - You don't even need to create, for instance, your repository class, and you'll be able to test a class that would use this repository
  • Keeps you away from external resources - helps in the sense you don't need to access databases, or to call web services, or to read files, or to send emails, or to charge a credit card, and so on...

In an interview, I'd recommend including that mocking is even better when developers use dependency injection, once it allows you to have more control, and build tests more easily.

Samuel Carrijo
Of course, on the *bad* side of Mock Objects, is the fact that when the real class interface changes someone has to run around finding and updating the Mocks and in the meantime all those "successful" tests are lies.
Zan Lynx
That can be mitigated if one of your tests includes verifying the interface hasn't changed. That test fails, you know your mocks will be wrong.
Robert P
But it doesn't change the fact that the subscribers to the interface are broken.
Gutzofter
@Gutzofter Depending on the mock libraries and IDE you use, when changing an interface, it also changes the mock calls to that interface.
Samuel Carrijo
@Samual - I've been spending a lot of time thinking about this. What if you have a lot of subscribers to the interface (including dynamic languages) and it changes, then you have a lot of broken subscribers (tests). I'll probably have to reread some Martin Fowler to get a better perspective on this. Do you have any references that looks into this problem?
Gutzofter
@Gutzofter I don't know how it works in dynamic languages, but Moq in c# and EasyMock in Java don't require you to pass the method name as a string parameter (error prone), but generates a compile error in case the class doesn't have this method in its api. It was a real pain when this wasn't true. I'm not sure how dynamic languages handle this (but if you use the real class, won't you also need to change your tests AND working code accordingly?)
Samuel Carrijo
@Samuel - I've done some C#. I used Rhino Mocks. I'm also a strong advocate of Arrange Act Assert. Just when they were transition away the string method name and after. That is a problem with the mocks I'm using now. Just last week concerning leaning on the compiler, this came up here: http://ayende.com/Blog/archive/2010/05/05/i-like-strong-typing-and-compilation-errors.aspx concerning JavaScript. I may switch to using a double dispatch when using multiple sinks for the interface.
Gutzofter
+2  A: 

Mock objects/functions can also be useful when working in a team. If you're working on a part of the code base that depends on a different part of the code base that some else is responsible for - which is still being written or hasn't been written yet - a mock object/function is useful in giving you an expected output so that you can carry on with you're work without being held up waiting for the other person to finish their part.

Mike Lowen
+4  A: 

When unit testing, each test is designed to test a single object. However most objects in a system will have other objects that they interact with. Mock Objects are dummy implementations of these other objects, used to isolate the object under test.

The benefit of this is that any unit tests that fail generally isolate the problem to the object under test. In some cases the problem will be with the mock object, but those problems should be simpler to identify and fix.

It might be an idea to write some simple unit tests for the mock objects as well.

They are commonly used to create a mock data access layer so that unit tests can be run in isolation from the data store.

Other uses might be to mock the user interface when testing the controller object in the MVC pattern. This allows better automated testing of UI components that can somewhat simulate user interaction.

An example:

public interface IPersonDAO
{
    Person FindById(int id);
    int Count();
}

public class MockPersonDAO : IPersonDAO
{
    // public so the set of people can be loaded by the unit test
    public Dictionary<int, Person> _DataStore;

    public MockPersonDAO()
    {
        _DataStore = new Dictionary<int, Person>();
    }

    public Person FindById(int id)
    {
        return _DataStore[id];
    }

    public int Count()
    {
        return _DataStore.Count;
    }
}
Benny Hallett
+2  A: 

Just to add on to the fine answers here, mock objects are used in top-down or bottom-up structural programming (OOP too). They are there to provide data to upper-level modules (GUI, logic processing) or to act as out mock output.

Consider top-down approach: you develop a GUI first, but a GUI ought to have data. So you create a mock database which just return a std::vector<> of data. You have defined the 'contract' of the relationship. Who cares what goes on inside the database object - as long as my GUI list get a std::vector<> I'm happy. This can go to provide mock user login information, whatever you need to get the GUI working.

Consider a bottom-up approach. You wrote a parser which reads in delimited text files. How do you know if it is working? You write a mock 'data-sink' for those object and route the data there to verify (though usually) that the data are read correctly. The module on the next level up may require 2 data sources, but you have only wrote one.

And while defining the mock objects, you have also define the contract of how the relationship. This is often used in test-driven programming. You write the test cases, use the mock objects to get it working, and often than not, the mock object's interface becomes the final interface (which is why at some point you may want to separate out the mock object's interface into pure abstract class).

Hope this helps

Extrakun
A: 

Here are the a few situations where mocking is indispensable:

  1. When you are testing GUI interaction
  2. When you are testing Web App
  3. When you are testing the code that interacts with hardware
  4. When you are testing legacy apps
Ngu Soon Hui
+1  A: 

I will go a different direction here. Stubbing/Faking does all of the things mentioned above, but perhaps the interviewers were thinking of mocks as a fake object that causes the test to pass or fail. I am basing this on the xUnit terminology. This could have lead to some discussion about state testing verses behavior / interaction testing.

The answer they may have been looking for is: That a mock object is different than a stub. A stub emulates a dependency for the method under test. A stub shouldn't cause a test to fail. A mock does this and also checks how and when it is called. Mocks cause a test to pass or fail based on underlying behavior. This has the benefit of being less reliant on data during a test, but tying it more closely to the implementation of the method.

Of course this is speculation, it is more likely they just wanted you to describe the benefits of stubbing and DI.

MarcLawrence
A: 

To take a slightly different approach (as I think mocks have been nicely covered above):
"Take a database--if you're writing test code, you may not want that test hooked up live to the production database where actual operations will be performed."

IMO a bad way of stating the example use. You would never "hook it up to the prod database" during testing with or without mocks. Every developer should have a developer-local database to test against. And then you would move on test environments database then maybe UAT and finally prod. You are not mocking to avoid using the live database, you are mocking in order that classes that are not directly dependent on a database do not require you to set up a database.

Finally (and I accept I might get some comments on this) IMO the developer local database is a valid thing to hit during unit tests. You should only be hitting it while testing code that directly interacts with the database and using mocks when you are testing code that indirectly access the database.

mlk