Over a million developers have joined DZone.

Deliver a Good Return of Investment Unit Testing Code

· Java Zone

Discover how AppDynamics steps in to upgrade your performance game and prevent your enterprise from these top 10 Java performance problems, brought to you in partnership with AppDynamics.

It has always been my belief that comprehensive integration/functional testing of code is far far more important/productive than to blindly try to achieve 100% unit testing code coverage. I believe:
a) Good integration/functional tested code will always deliver more test coverage then unit testing code.
b) Functional/Integration testing code allows us to capture our programming errors as early as possible, and avoid “big bang” integration errors at the end.

Thus, I always have “healthy and interesting” discussion with developers where they always believe:

  1. Achieve high percentage of unit testing code coverage is very important.
  2. Every class delivered must be “unit testable”, all dependency classes/resources should be “mocked”, even though it sometimes is very difficult  and time consuming to setup such mock objects.
  3. 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, or any things that make our class not "unit testing friendly" are bad.

Don't get me wrong, I am not 100% against the points above, and I do understand the importance of unit testing. However, I will not go to extremes spending extra effort to achieve 100% unit test code coverage. Thus, as Software Development Manager, it's my belief and I  encourage my team to deliver a good Return of Investment (ROI) testing code. As Java resources are expansive and we need to take of maintaining non productive unit testing code we deliver into consideration.

 So, what is considered a good ROI code:

  • It's should be “black box” test, where developers pass certains parameters to a method, execute the method and verify the return value against the expected result, we should not care how the method is executed, and what underlying resources being called.
  • The testing code should be easily promoted to functional/integration testing code, why reinvent the wheel?
  • The testing code should design around your use cases, and right back to your application's features. Thus, using a HR application as an example, to unit test your annual leave application is always approved by your manager would produce good ROI value. But to unit test simple getter or setter of your data object, or to mock a DAO on returning an employee object, or make utilities to read properties files or parsing a mock XML file does not produce good ROI value.

To explain this further, assuming I have a business delegate class, called OrderManager, which has a dependency on InventoryManager, AccountManager, and ShipmentManager.There is a method to check if a order should be processed or not, as code shown below: 

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

}

To unit test proceedOrder() method using Mock:

  1. First, create InventoryManager, AccountManager, and ShipmentManager mocks
  2. Instruct our mock framework on mock methods called, and tell the mock the expected sequence of the call, and set return for each mock call.
  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? 

  • It's breaking the black box testing approach, we are telling our mock framework step-by-step what mock methods will be call, and specifically ask them to return the value we set, and test method proceedOrder() returns a value with our expected result, when we already know what it will return in the first hand.
  • What happens if we want to change the implementation, like changing the calling sequence, or introduce new business logic, such as check if customer is VIP customer, who might have priority on getting his/her preferred shipment slot, do we have to change our testing code?
  • Even if our unit code coverage report shows that we have cover this method 100%, does that give us any value at all?

As an example, A good 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() method by placing product A with various quantities
3. Verify the result against expectedResult

So, to conclude, I believe that if unit testing code does not bring any 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 do not hear of engineers that create mock 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 (made of different rubbers), and conduct braking test on various surface (maybe on a rolling board with different surfaces), right?

Do share your views on this.

The Java Zone is brought to you in partnership with AppDynamics. AppDynamics helps you gain the fundamentals behind application performance, and implement best practices so you can proactively analyze and act on performance problems as they arise, and more specifically with your Java applications. Start a Free Trial.

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}