Play Framework and Guice: use providers in Guice modules

Play Framework has a Guice module. Unfortunately, its use is fairly limited compared to what Guice can do. In this post, I describe how it is configured on my current personal project.

Spring in Paris, when days last longer and pianists play in the street

In general, when I test classes that have dependencies, my favorite approach is to pass those dependencies to the constructor:

public class MyService {
	private final MyDependency myDependency;

	public MyService(MyDependency myDependency) {
		this.myDependency = myDependency;
	}
}

Which makes creating test harnesses with Mockito reasonably easy:

public class MyServiceTest extends UnitTest {
	@Test
	public void shouldComputeAResult() {
		MyDependency mockMyDependency = mock(MyDependency.class);
		when(mockMyDependency.findSomeValue()).thenReturn("some value");

		MyService service = new MyService(mockMyDependency);

		assertThat(service.computeSomething(), equalTo("result"));
	}
}

However, it appears that Guice, at least under version 1.1.1 of its Play module, can only be used with Play to inject into static members:

@InjectSupport
public class MyService {
	@Inject
	static MyDependency myDependency;
	// no constructor (a default constructor will be
	// generated automatically by Play Framework)
}

The @InjectSupport is what makes the Guice module detect that the class requires dependencies (a class that extends either com.google.inject.AbstractModule or play.modules.guice.GuiceSupport must also be present in the classpath).

This makes it hard to instrument classes under test, as the value for a mock instance of MyDependency is shared amongst all tests that run currently.

public class MyServiceTest extends UnitTest {
	@Test
	public void shouldComputeAResult() {
		MyDependency mockMyDependency = mock(MyDependency.class);
		when(mockMyDependency.findSomeValue()).thenReturn("some value");

		MyService service = new MyService();
		// static values are brittle;
		// they should not be touched in unit tests
		service.myDependency = mockMyDependency; // yuck!

		assertThat(service.computeSomething(), equalTo("result"));
	}
}

Many subtle problems may occur when injecting dependencies in this way. For example, all instances of MyServices used concurrently will point to the same dependencies instances, so it is possible that tests will behave in inconsistent ways. Also, it makes it harder to default to sensible (null) dependencies, since tests running in the same JVM will by default use dependencies set by the first test.

The solution I’m using is to add providers in your Guice module:

public class GuicyModule extends AbstractModule {
	@Override
	public void configure() {
		// no code needed
	}

	@Provides
	public MyService getMyService(MyDependency myDependency) {
		return new MyService(myDependency);
	}
}

In this way, you are making sure that the dependencies are passed as you wish. Also, it will not be necessary to add any sort of Guice-related code in my services:

public class MyService {
	private final MyDependency myDependency;

	public MyService(MyDependency myDependency) {
		this.myDependency = myDependency;
	}
}

The downside is that you do have a few more lines to maintain, which is never fun. Better than the alternative, though.

My thanks to David Gageot who told me about providers in Guice.

About Eric Lefevre-Ardant

Independent technical consultant.
This entry was posted in java, test and tagged , , . Bookmark the permalink.

1 Response to Play Framework and Guice: use providers in Guice modules

  1. Pingback: Playframework + Google Guice (EspaƱol) « Having fun with Play framework!

Comments are closed.