I want to develop a Service (A class method) that does the following. Receives some text, calls (POST to) some HTTP URL with that text as body, and retrieve the value of a cookie (SESSION_ID cookie) from the response.
If i were solving this in Java i would start with some test like this (This code doesn't compile I just wrote it in notepad):
- private CommunicationService testObj;
- private CookieValueExtractor cookieValueExtractor;
- private HttpClient httpClient;
- private HttpResponse response;
- @Before
- public void setup(){
- conf=new MockConfiguration();
- cookieValueExtractor=new MockCookieValueExtractor();
- httpClient=new MockHttpClient();
- response=new MockHttpResponse();
- testObj.setConfiguration(conf);
- testObj.setCookieValueExtractor(cookieValueExtractor);
- testObj.setHttpClient(httpClient);
- }
- @Test
- public void testSendRequestToHttpAndReturnSessionId(){
- Capture<HttpPost> httpPost=new Capture<HttpPost>();
- expect(httpClient.execute(capture(httpPost))).andReturn(response);
- expect(cookieValueExtractor.extractCookieByName(response,“SESSION_ID”)).andReturn(SESSION_ID)
- assertEquals(SESSION_ID,cookieValue);
- }
Taking all setup code out, and focusing on the test method, we can see what we expect our method will do.
1. It will retrieve a URL for a Configuration facility
2. It will use HttpClient to send a Post to that URL
3. It will call a CookieExtractor facility to extract the cookie value we are interested in.
4 It will return that cookie value to the caller.
It is pretty easy to understand.
I now have the same requirement in a Grails project. Of course i want to use the power of Groovy and Grails, so i check the HttpBuilder library out, read a little bit about it and start to work.
The httpBuilder basically works by passing two parameters. A Map, with all the options (Including body, Path, etc) and a Closure that will get the response from the invocation.
Also i need to obtain some values like the URL from grails configuration files.
At the end, going to my implementation class and my test many times while developing(which i usually don’t need to in Java) i end with the following.
- configureConfigurationHolder()
- httpBuilderMock.demand.post{
- a,b ->
- assertEquals("test_payment.pl",a["path"])
- resp.init()
- assertEquals("123123", sessionId)
- }
- moneybookerService.httpBuilder=mockService
- moneybookerService.makeRequest()
- httpBuilderMock.verify mockService
- }
- expando.url=""
- expando.path="test_payment.pl"
- ConfigurationHolder.config=["moneybooker":expando]
- }
- class DummyResponseWithCookie{
- def headers
- expando.name="SESSION_ID"
- expando.value="123123"
- outerExpando.elements=[expando]
- headers=["Set-Cookie":outerExpando]
- }
A lot of work. The main problems that I find are
First and most important. How do i Test closures?. In my case, i had to mock a response object (DummyResponseWithCookie) and because i knew what i wanted the closure to do, call the closure with that mock. But this doesn’t look good. I’m calling the closure in the demand of the mock of httpBuilder. So this test is testing more than what it should. But i don’t know how to test the closure on its own.
Second, the way to mock the configuration holder. Just setting static variables doesn’t seem very right.
Third. This is probably lack of practice but It took me longer to write this test, and was really difficult to think exactly what i wanted to achieve in my service, what needed to be mocked and in general how to approach it in a TDD way.
I really like Groovy, and Grails. I just don’t know how to approach TDD and Unit testing in general in a way that feels as comfortable as with Java.