Category Archives: Test

Groovy och Grizzly http unit test

Hur ofta är det inte som man stöter på legacy kod som vill göra ett externt TCP anrop (socket, http, webservice eller något annat) och så sliter man sitt hår för att hitta det optimala sättet att skriva ett unit test för koden (som naturligtvis inte finns där från början) för att kunna göra den lite mindre legacy.

Jag stötte på detta igen häromdagen och bestämde mig för att testa ett groovy-grepp på problemet. Det visade sig vara en strålade idé (ödmjukt).

Säg att vi har följande lilla demoklass att testa.

package demo;

import java.io.IOException;
import java.net.HttpURLConnection;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

public class HttpCallingBean {    

    public void sendMessage(String message) {
        HttpClient httpClient = new HttpClient();
        PostMethod postMethod = new PostMethod("http://localhost:8282");

        try {
            StringRequestEntity entity = new StringRequestEntity(message);
            postMethod.setRequestEntity(entity);
            httpClient.executeMethod(postMethod);
            if(postMethod.getStatusCode() != HttpURLConnection.HTTP_OK){
                throw new RuntimeException("Not ok!"); // Only a demo...
            }

        }catch(IOException e){
            e.printStackTrace(); // Only a demo...

        }finally{
            postMethod.releaseConnection();
        }
    }
}

Vill vi skriva ett test för detta (utan att bryta ut anropet i en annan klass och mocka den) så måste vi sätta upp en liten lyssnare på porten 8282 på localhost, vi vill dessutom integrera detta i junittestet så att lyssnaren startas och stoppas tillsammans med tester. Med Grizzly och Groovy visar det sig att detta är mycket enkelt. Nedan följer testkoden för klassen ovan

package demo

import groovy.util.GroovyTestCase
import com.sun.grizzly.http.SelectorThread
import com.sun.grizzly.tcp.Adapter
import com.sun.grizzly.tcp.Request
import com.sun.grizzly.tcp.Response
import com.sun.grizzly.util.buf.ByteChunk
import java.net.HttpURLConnection

class HttpCallingBeanTest extends GroovyTestCase {

 void testSayHello()throws Exception {
 def st = new SelectorThread()
 try{
 st.port = 8282
st.adapter = new BasicAdapter()
 st.listen()

 HttpCallingBean beanUnderTest = new HttpCallingBean()
 beanUnderTest.sendMessage("Hello grizzly")

 }finally{
 st.stopEndpoint()
 }
 }
}

class BasicAdapter implements Adapter {
 public void service(Request request, Response response) {
 def content = new ByteChunk()
 request.doRead(content)
 def bytes = null
 if(content.equals("Hello grizzly")){
 response.status = HttpURLConnection.HTTP_OK
 bytes = 'Success'.bytes<strong>
 }else{
 response.status = HttpURLConnection.HTTP_BAD_REQUEST
 bytes = 'Failure'.bytes
 }

 def chunk = new ByteChunk()
 chunk.append(bytes, 0, bytes.length)
 response.contentLength = bytes.length
 response.contentType = 'text/html'
 response.outputBuffer.doWrite(chunk, response)
 response.finish()
 }

 public void afterService(Request request, Response response) {
 request.recycle()
 response.recycle()
 }

 public void fireAdapterEvent(string, object) {}
}

Här har vi alltså ett unittest som startar en Grizzly SelectorThread och kopplar en enkel adapter (BasicAdapter) till den. Adaptern läser vad som kommer in och svarar med OK eller BAD_REQUEST. När testet är kört stoppas selector tråden i finally blocket och vi har ett komplett test för bönan med dess externa anrop i ett enda unittest.