Five Unit Test Tips: #1: Use the data store

I’ve looked over some of my code lately, and found ways that I often improve my tests. I’m planning on writing a blog post for each of my five favorites.

First out: Using the data storage. I upgraded our API for billing customers. I had a few compilation errors in my code, as the API had changed somewhat. After fixing these errors, I was left with a test that broke mysteriously with a MethodNotFoundException. I located the test and found that it was close to unreadable. After examining it further, I found that it was trying to do was simple, but hidden in technical code.

I had the following test (the design is real, the details have been changed to protect the guilty):

@Test
public void shouldBillExtraForErrors() {
   BillingService billingService = someService.getBillingService();
   MethodCallLoggingInterceptor interceptor =
        MethodCallLoggingInterceptor.for(billingService);
   someService.setBillingService((BillingService)interceptor);
 
   Request requestWithError = createCustomerRequestWithError(CUSTOMER_ID);
   someService.process(requestWithError);
 
   Method method = BillingService.class.getMethod("sendBillingEvent", ....);
   MethodCall[] callsToBilling = interceptor.getMethodCallsFor(method);
 
   assertEquals(2, callsToBilling);
   assertEquals(CUSTOMER_ID, callsToBilling[0].getParams()[0]);
   assertEquals(BillingCode.RECEIVED_REQUEST, callsToBilling[0].getParams()[3]);
   assertEquals(CUSTOMER_ID, callsToBilling[1].getParams()[0]);
   assertEquals(BillingCode.INVALID_REQUEST, callsToBilling[1].getParams()[3]);
}

When the parameters to sendBillingEvent changed and the test started throwing MethodNotFoundException I changed it to the following:

@Test
public void shouldBillExtraForErrors() {
   Request requestWithError = createCustomerRequestWithError(CUSTOMER_ID);
   someService.process(requestWithError);
 
   BillingFinder finder = BillingFinder.forCustomer(CUSTOMER_ID);
   finder.setBillingCode(BillingCode.RECEIVED_REQUEST);
   assertEquals(1, billingRepository.count(finder));
   finder.setBillingCode(BillingCode. INVALID_REQUEST);
   assertEquals(1, billingRepository.count(finder));
}

The lessons:

  • Ask about the outcome, not about the method calls that get you there
  • Avoid reflection in tests. It’s bound to be brittle
  • Mocks and similar methods are overrated

(In tip #2, I will show how I preserve the data store metaphor without giving up execution speed)

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.

Print This Post Print This Post
blog comments powered by Disqus
Creative Commons Attribution 3.0 Unported
This work is licensed under a Creative Commons Attribution 3.0 Unported.