Testable Classes versus Reflection

Code we write often gets run in two different contexts – ‘production mode’ and ‘unit testing’. A common chain of thought is that the design of a class is purely on how code runs in production, unit testing being some necessary evil but not something to influence or modify the ‘glorious design’.

Here is my example.

import javax.persistence.Id;

public class Customer {

	@Id
	private Long id;

	public Long getId() {
		return id;
	}
}

My problem now is that I have a test where I want to assert that, given a customer, my audit service will audit the customer id. How to set the id field? In ‘production mode’ the id should be set by my persistence provider. But what about in my unit test?

Another example:

import javax.ejb.EJB;

public class CustomerServiceEJB {

	@EJB
	private AuditService auditService;

	public void onCustomerCreate(Customer customer) {
		auditService.auditCustomerCreation(customer);
	}
}

How do I inject an AuditService? The answer given is always the same, and always as enthusiastic – reflection. But not called reflection – reflection has negative connotations. We use something with a nice name – maybe Whitebox or Deencapsulation. Surely with deencapsulation the clue / irony is in the title. The next time I’m faced with this I’m going to create my own version called TightCoupler.

From the implied irony it might be obvious that I don’t hold with that. I believe the unit testing is part of the ‘developer system’ which can often be neglected or completely ignored.

Typically in Agile development we have a top level requirement as a ‘story’. My stories go like this:

  • As an agile developer I want tests that enable refactoring by not containing hard-coded method names.
  • As a developer in a statically-typed language I want tests that enable compile-type checking by not containing hard-coded method names.
  • As a developer I want components that can have state set both by a JEE container or by test classes.

My problem with the whole thing is this:

  • values that can only be injected in the container are not context-agnostic and can rely on anti-refactoring practices to be useful.
  • encapsulation hides how a class works from its clients, deencapsulation in tests is just an anti-pattern.  
  • believing method accessibility is your enemy when you’ve got hard-coded method names in tests (or missing tests) is a bigger problem that having setters you didn’t put in a class diagram.

Or we can all carry on writing tomorrow’s legacy code… today.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s