Java Reference
In-Depth Information
@Test
public void testGetContentOk() throws Exception {
MockHttpURLConnection mockConnection = new MockHttpURLConnection();
mockConnection.setExpectedInputStream(
new ByteArrayInputStream("It works".getBytes()));
TestableWebClient client = new TestableWebClient();
client.setHttpURLConnection(mockConnection);
String result = client.getContent( new URL(" http://localhost") );
assertEquals("It works", result);
}
In this code, we configure TestableWebClient B so that the createHttpURLConnection
method returns a mock object. Next, the getContent method is called C .
This is a common refactoring approach called method factory refactoring, which is
especially useful when the class to mock has no interface. The strategy is to extend
that class, add some setter methods to control it, and override some of its getter meth-
ods to return what we want for the test. In the case at hand, this approach is okay, but
it isn't perfect. It's a bit like the Heisenberg uncertainty principle: the act of subclass-
ing the class under test changes its behavior, so when we test the subclass, what are we
truly testing?
This technique is useful as a means of opening up an object to be more testable,
but stopping here means testing something that's similar to (but not exactly the same
as) the class we want to test. It isn't as if we're writing tests for a third-party library and
can't change the code—we have complete control over the code to test. We can
enhance it and make it more test friendly in the process.
B
C
7.4.4
Second attempt: refactoring by using a class factory
Let's apply the Inversion of Control pattern, which says that any resource we use needs
to be passed to the getContent method or WebClient class. The only resource we use
is the HttpURLConnection object. We could change the WebClient.getContent signa-
ture to
public String getContent(URL url, HttpURLConnection connection)
This means we're pushing the creation of the HttpURLConnection object to the caller
of WebClient . But the URL is retrieved from the HttpURLConnection class, and the sig-
nature doesn't look nice. Fortunately, there's a better solution that involves creating a
ConnectionFactory interface, as shown in listings 7.8 and 7.9. The role of classes
implementing the ConnectionFactory interface is to return an InputStream from a
connection, whatever the connection might be ( HTTP , TCP / IP , and so on). This refac-
toring technique is sometimes called a class factory refactoring. 3
3
J. B. Rainsberger calls it Replace Subclasses with Collaborators: http://www.diasparsoftware.com/tem-
plate.php?content=replaceSubclassWithCollaborator.
 
 
 
 
 
 
Search WWH ::




Custom Search