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)
This work is licensed under a
Creative Commons Attribution 3.0 License.
Print This Post