Recently I was working on a Domain Forwarding Server. For Ex. if you request for http://google.com and Google wants to redirect you to http://google.in, then this server handles the redirection for you. There are many permutations and combination of how you want to forward your domain to another domain.
First pass, I wrote a tests:
1
2
3
4
5
6
7
8
| @Test
public void permanentlyRedirectDomainsWithPath() {
when(request.hostName()).thenReturn("google.com");
when(request.protocol()).thenReturn("HTTP/1.1");
when(request.path()).thenReturn("/index.html");
domain.setDomain("google.com");
domain.forwardPath(true);
domain.setForward("google.in"); |
@Test
public void permanentlyRedirectDomainsWithPath() {
when(request.hostName()).thenReturn("google.com");
when(request.protocol()).thenReturn("HTTP/1.1");
when(request.path()).thenReturn("/index.html");
domain.setDomain("google.com");
domain.forwardPath(true);
domain.setForward("google.in");
9
| response = service.processMessage(request); |
response = service.processMessage(request);
10
11
12
13
| assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
} |
assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
}
Note that since the request is an expensive object to build, I’m stubbing it out. While domain is more of a value object in this case, so its not stubbed/mocked out.
This test has a lot of noise. All the stubbing logic was just making this test very difficult to understand what was going on. So I extracted some methods to make it more meaningful and hide the stubbing logic.
1
2
3
4
5
6
7
| @Test
public void permanentlyRedirectDomainsWithPath() {
setDomainToBeRedirected("google.com");
setDestinationDomain("google.in");
shouldRedirectWithPath();
setHostName("google.com");
setPath("/index.html"); |
@Test
public void permanentlyRedirectDomainsWithPath() {
setDomainToBeRedirected("google.com");
setDestinationDomain("google.in");
shouldRedirectWithPath();
setHostName("google.com");
setPath("/index.html");
8
| response = service.processMessage(request); |
response = service.processMessage(request);
9
10
11
12
| assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
} |
assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
}
Looking at this code it occurred to me that I could use Fluent Interfaces and make this really read like natural language. So finally I got:
1
2
3
4
| @Test
public void permanentlyRedirectDomainsWithPath() {
request("google.com").withPath("/index.html");
redirect("google.com").withPath().to("google.in"); |
@Test
public void permanentlyRedirectDomainsWithPath() {
request("google.com").withPath("/index.html");
redirect("google.com").withPath().to("google.in");
5
| response = service.processMessage(request); |
response = service.processMessage(request);
6
7
8
9
| assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
} |
assertStatus(StatusCode.PermanentRedirect);
assertLocation("google.in/index.html");
assertStandardResponseHeader();
}
10
11
12
13
14
| private ThisTest request(String domainName) {
when(request.hostName()).thenReturn(domainName);
when(request.protocol()).thenReturn("HTTP/1.1");
return this;
} |
private ThisTest request(String domainName) {
when(request.hostName()).thenReturn(domainName);
when(request.protocol()).thenReturn("HTTP/1.1");
return this;
}
15
16
17
| private void withPath(String path) {
when(request.path()).thenReturn(path);
} |
private void withPath(String path) {
when(request.path()).thenReturn(path);
}
18
19
20
21
| private ThisTest redirect(String domainName) {
domain.setDomain(domainName);
return this;
} |
private ThisTest redirect(String domainName) {
domain.setDomain(domainName);
return this;
}
22
23
24
25
| private ThisTest withPath() {
domain.forwardPath(true);
return this;
} |
private ThisTest withPath() {
domain.forwardPath(true);
return this;
}
26
27
28
| private void to(String domainName) {
domain.setForward(domainName);
} |
private void to(String domainName) {
domain.setForward(domainName);
}
Finally after introducing Context Objects, I was able to make the code even more easier to read and understand:
1
2
3
4
5
6
7
8
9
| @Test
public void redirectSubDomainsPermanently() {
lets.assume("google.com").getsRedirectedTo("google.in").withPath();
response = domainForwardingServer.process(requestFor("google.com/index.html"));
lets.assertThat(response).contains(StatusCode.PermanentRedirect)
.location("google.in/index.html").protocol("HTTP/1.1")
.connectionStatus("close").contentType("text/html")
.serverName("Directi Server 2.0");
} |
@Test
public void redirectSubDomainsPermanently() {
lets.assume("google.com").getsRedirectedTo("google.in").withPath();
response = domainForwardingServer.process(requestFor("google.com/index.html"));
lets.assertThat(response).contains(StatusCode.PermanentRedirect)
.location("google.in/index.html").protocol("HTTP/1.1")
.connectionStatus("close").contentType("text/html")
.serverName("Directi Server 2.0");
}
This entry was posted
on Saturday, December 27th, 2008 at 7:20 PM and is filed under Agile, Testing.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.