TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 241 other followers

  • Sleepless Nights…

    December 2009
    S M T W T F S
    « Nov   Jan »
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
  • Blog Stats

    • 865,600 hits

Unit testing with MockHttpSession and Guice

Posted by David Chandler on December 14, 2009

The more I learn about Guice, the more I like it. First, I discovered I could get access to the HttpSession inside my Guice-injected service classes (which are in turn called from my Guice-injected gwt-dispatch ActionHandlers) like this:

public class ROAUserServiceImpl implements ROAUserService
{
	@Inject
	Provider<HttpSession> httpSession;

	@Override
	public LoginInfo login(String requestUri)
	{
		httpSession.get().invalidate();
		...
	}
	...
}

Then came the unhappy moment that I ran my unit tests, which call ActionHandlers, all of which call ROAUserService to verify that the user is logged in. In my unit test environment, Guice cannot inject an HttpSession because my tests are not currently running in a servlet container; thus, every test fails.

I could bring in HttpUnit / ServletRunner, but that is really overkill for what I’m trying to do at this point, which is just to simulate one session attribute being set to represent the logged in user.

I could also create a mock ROAUserService and inject that in my ActionHandlers instead of the real one. But I’d prefer to use the real service for testing, and sooner or later, I’ll need to stuff something else in session, anyway.

Enter Guice Providers.

In the example above, the HttpSession is being injected by way of a Guice Provider, which in the real app, comes for free when your Guice injector includes a ServletModule. Fortunately, we can easily tell Guice to provide a mock HttpSession by using the @Provides annotation in a plain old AbstractModule (no ServletModule required):

package com.turbomanage.gwt.server.guice;

import javax.servlet.http.HttpSession;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.roa.test.mock.MockHttpSession;

public class DispatchTestModule extends AbstractModule
{
	@Override
	protected void configure()
	{
		// application bindings here
	}

	@Provides
	HttpSession getMockSession()
	{
		return new MockHttpSession();
	}
}

I could probably snag a mock session from some other framework, but all I need to do is get and set attributes, hence:

package com.roa.test.mock;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;

public class MockHttpSession implements HttpSession
{
	private Map<String, Object> attributes = new HashMap<String, Object>();

	@Override
	public Object getAttribute(String name)
	{
		return attributes.get(name);
	}

	@Override
	public void setAttribute(String name, Object value)
	{
		attributes.put(name, value);
	}

	// All other methods auto-generated
	...
}

Now my TestCase setUp() method can simulate user login, logout, etc. by calling the real ROAUserService, which Guice provides with our mock HttpSession.

		...
		User u = addTestUser();
		Injector inj = Guice.createInjector(..., new DispatchTestModule());
		ROAUserService userService = inj.getInstance(ROAUserService.class);
		userService.login(...);

Guice Providers can also accept user-defined annotations to allow you to select among multiple implementations of a provided class. That might be another handy testing tool…

Advertisements

3 Responses to “Unit testing with MockHttpSession and Guice”

  1. Dhanji said

    Another very simple way to mock the session is to fire a request to GuiceFilter with a mock request (which provides a mock session).

    You can then configure your module with just the servlet you are trying to test, and that way the entire code path gets exercised.

    Dhanji.

    • Thanks, Dhanji. Because I’m using GWT RPC, in order to test the entire code path, I need a way to generate the RPC requests to my GWT RemoteServiceServlet, which requires GWTTestCase. The tests I’m writing about here are purely server-side unit tests , but I can definitely use this idea when I bring in GWTTestCase later on.

  2. This makes life so much easier. I replaced all of Mockito’s mock(HttpSession.class) with these real session objects. Thanks David.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: