IgorShare Thoughts and Ideas

Consulting and Training

Archive for September 5th, 2008

Mocking, embedded-Jetty and expectations for outgoing HTTP requests in Java

Posted by Igor Moochnick on 09/05/2008

If your classes in Java are executing outgoing HTTP calls it’s not easy to unit-test them. In many cases it requires to set-up separate web servers and deploy a test-verification code. I’m going to give you a way to do it in-line, just as you do it with any other unit-test.

In order to do this we’ll use embedded-Jetty. We’ll host Jetty inside the unit-testing framework.

For our example I’m going to use a TestNG unit-testing framework, but, as you can guess, you’re welcome to use any other you see fit.

1. First of all we need to initialize Jetty. We’re going to do it in @BeforeClass method:

private Server server;
private String returnUrl;

@BeforeClass
@Parameters({ "test-jetty-port" })
public void setUpJetty(@Optional("8123") int testPort) throws Exception
{
	server = new Server(testPort);

	Handler handler = new AbstractHandler()
	{
	    public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
	        throws IOException, ServletException
	    {
	        handleHttpRequest(target, request, response);
	    }
	};
	
	returnUrl = "http://localhost:" + Integer.toString(testPort) + "/test";
	
	server.setHandler(handler);

	server.start();
}

2. In order to consume all the incoming HTTP traffic we’re going to define a handler (we’re going to discuss other opportunities in the following posts). Note that the incoming HTTP traffic is stored inside the HttpTester parser class:

private HttpTester requestTest = new HttpTester();

private String getRequestString(HttpServletRequest request) throws Exception
{
	ServletInputStream reqz = request.getInputStream();
	int contentLen = request.getContentLength();
	if (contentLen == -1)
		return request.toString();
	
	byte[] buff = new byte[contentLen];
	int realLen = reqz.read(buff);
	
	Assert.assertEquals(realLen, contentLen, "Content length from parameter should be equal to the real content length");
	
	return request.toString() + new String(buff);
}

public void handleHttpRequest(String target, HttpServletRequest request, HttpServletResponse response)
{
	try
	{
		requestTest.parse( getRequestString(request) );
	}
	catch(Exception e)
	{
		Assert.fail("Failed to parse the incoming request.", e);
	}
	
    response.setContentType("text/html");
    response.setStatus(HttpServletResponse.SC_OK);
    ((Request)request).setHandled(true);
}

3. And this is how you can define your test fixture:

@Test
public void jobReport_returns_POST_reply() throws Exception
{
    String xml = "<xml>some-data-here</xml>";

    object-to-test.send_post(returnUrl, xml);
    
    Assert.assertEquals(requestTest.getMethod(), "POST");
    Assert.assertEquals(requestTest.getURI(), "/test");
    Assert.assertEquals(requestTest.getContent(), xml);
}

4. After all the tests are done, don’t forget to shutdown the Jetty server:

@AfterClass
public void tearDownJetty() throws Exception
{
	server.stop();
}
Advertisements

Posted in Java, Jetty, Mocking, TestNG, Unit Testing | 1 Comment »

 
%d bloggers like this: