Monday, May 21, 2007

100% Unit Test Code coverage using Mock, does it really matter?

I always believe delivering a comprehensive integration/functional testing code is far far more important/productive than blindly try to achieve 100% unit testing code coverage. I believe:
a) A integration/functional testing code will always deliver more test coverage then unit testing code.
b) Integration testing code allows us to capture our program error as earlier as possible, and avoid “big bang” integration error at the end.

Thus, I always have “heat and interesting” discussion with some developers where they always believe:
a) Achieve high percentage of unit testing code coverage is very important
b) unit testing code must be “unit testable”, all dependency classes/resources should be “mocked”, even sometime is so so difficult to mock such objects.
c) if our code is not testable, that must be something wrong with our design. We have to change our code to make it testable. Thus making our class final, or our class not implementing an interface, or using static methods are all bad!.

Don't get me wrong, I am not 100% against points above, and I understand important of unit testing. But believe the unit testing code we deliver must return good “Return of Investment” (ROI). Investment here mean our effort of delivering/maintaining the unit testing code. A good ROI unit testing code have the following characteristic:
a) It use “black box” approach , where we pass parameters to a method, test the method and we verified the return value against expected result, we should not care how's the methods executed, and what underlying resources being called.
b) The testing code should be easily promoted to functional/integration testing code, why reinvent the wheel?
c) The testing code must drafted base on agree use case, and tight back to your application's features. Thus, using HR application as an example, to unit test you annual leave application is always approved by your manager produce good ROI value. but to unit test your database connection pooling utilities, or utilities to read properties files or parsing a fake XML file does not produce good ROI value.

To illustrate what I mean by good ROI unit testing code, consider the following examples:


Public class OrderManager {
public boolean proceedOrder(OrderVO anOrder) {
return ( inventoryManager.hasStock(anOrder) &&
accountManager.customerGoodCreadit(anOrder.getCustomer()) &&
shipmentManager.shipmentDateOK(anOder.getPreferShipmentDate()
);

}


To unit test proceedOrder() methods using Mock:

1. First, create InventoryManager, accountManager, and shipmentManager mocks

2. Instruct our mock framework on mock methods that called, and for each mock methods call, we instruct expected return value.
3. And finally, we test return value with our expected result, and ensure mock methods being called.

Does the above code give us good ROI? IMHO, it does not...

a) It's breaking the black box testing approach, we are telling our mock framework steps by steps what mock methods will be call, and specifically ask them to return the value we set, and test method proceedOrder() return value with our expected result, which we already know what it will return in the first hand.

What happen if we wants to change the implementation, do we have to change our testing code as well.

b) It does not bring any business value...

A ROI testing code for the above use case:
1. Set a InventoryManager product (say product “A”) quantities to a specific amount (say 50)

2. test the proceedOrder() by placing product A with various quantities
3. Verify the result against expectedResult

So, to conclude, if a unit testing code does not produce good ROI, do spend more time on delivering functional/integration testing code, and delivering good "ROI" usable code coverage

Apply my points to Automobile industries, we will not hear an engineer that create mock of car tires, or create a mock for road surface to test a car braking system, he/she will actually “integrate” the braking system with a set of tires (make by different rubbers), and conduct braking test on various surface (maybe on a rolling board with different surfaces)

Share me your thoughts...