If you do Behavior Driven Development (BDD) or in less extend applicable if you do Test Driven Development (TDD), you will definitely get to a situation where you need to know that a certain method has been call but you are not interested in what is going on inside of this method. You don’t want to check whether the state of an object has been changed. It is responsibility to another unit test – “Try to use only one assert per test” – (Behavior Driven Development)
So, Nothing new here. I can use a mock object and specify the expected behavior I need. However, the complication comes when the method that I want to mock is specified in the same class I am testing. Example of this would be some service object that has method to retrieve data from a database and another method in the same class that filters this collection. How do we mock the database access method in order to verify the behavior of the filter method?
public class SomeClass { Collection retrieveSomeData(){ // goes to db.}
Collection filterBySomeCriteria(){ Collection all = retrieveSomeData(); // apply some rules to filter return filteredCollection; } }
|
If it is not easy to verify the behavioral specification of a specific context, then it should be refactor via Template, Strategy or some other form of collaboration. This is definitely very good principle that I follow a lot. One of the primary reasons for me to use BDD/TDD is to be able to design easily testable and verifiable behavior as well as a simple overall abstraction of a problem.
- Another solution is to create something like a proxy object, which overrides the method with some stub implementation. This is definitely possible and it is a technique that I used to do a lot in the past when testing methods that use Singletons objects. (Service Locator Patter - thankfully not any more with DI). However, it is as unnatural as to try to set specific data to db and then retrieved before verifying.
- Sometimes however, you probably don’t want to refactor similar implementation to another collaborating object (because of “Cohesion”, “Completeness”, “Convenience”, “Consistency” or some other reason). In situation like that, we can very easily create a proxy of the object under test and stub/mock the method that we want. We can create such an object by ourselves, similar to 2). However, much more convenient is to use some framework like EasyMock.
In EasyMock, we can mock not only against interfaces (much preferable) but against actual classes and even the class under test. The example above would be:
public void testShouldFilterBySomeCriteriaWhenThereAreMoreThanOneElements() { // create mock control for this class MockControl someClassControl = createClassControl(SomeClass.class, new Method[] { SomeClass.class.getMethod("retrieveSomeData", new Class[] {}) }); // create the actual class under test. SomeClass someClass = (SomeClass) someClassControl.getMock(); // expected returned result for the mocked method. Collection retrievedData = Arrays.asList(new Object[] { object1, object2 }); // set the expectations someClassControl.expectAndReturn(someClass.retriveSomeData(), retrievedData); classControl.reply();
assertEquals("One entry should be filtered", 1, someClass.filterBySomeCriteria().iterator.size());
// since we need this more as a stub rather than a mock, // it is not advisable to verify the expected behavior // anyway, if you really need to classControl.verify(); }
|
As everything else, we should be careful not to abuse this kind of testing.
Probably you want to stress this a lot when it comes to Mocks