Atom Feed SITE FEED   ADD TO GOOGLE READER

Overriding Bindings in Guice

In our functional tests, we prefer to launch an application that closely resembles the production one. This means using the production modules in a proper staging environment. Even with automating scripts, setting up the environment is time consuming and tedious - it requires database install and configuration, permissions, SSL certificates, and remote services to be running and available:
public class ProductionModule extends AbstractModule {
protected void configure() {
bind(LoginService.class).to(RemoteLoginService.class);
bind(DataStore.class).to(MySqlDatabase.class);
bind(BillerConnection.class).to(SecureBillerConnection.class);
bind(LoggingEngine.class).to(DistributedLoggingEngine.class);
}
}

Since proper functional tests are so labour intensive, we take shortcuts! We can make a decent approximation of production by replacing some production services with lightweight fakes. For example, all of our functional tests require a login server to authenticate users. But for most tests login isn't interesting and this is just a wasted effort. We'd rather just fake login for unrelated functional tests.

Modular Modules


The best solution to this problem is to split the login stuff into its own module:
public class ProductionLoginModule extends AbstractModule {
protected void configure() {
bind(LoginService.class).to(RemoteLoginService.class);
}
}

In the functional test server we can use a FakeLoginModule rather than the ProductionLoginModule. It provides the same bindings, but its entirely in-memory and configuration free. This approach is simple, manageable and maintainable. It's the best way to mix production and test code.

Overrides via Inheritance


There's also a quick-and-dirty approach to creating test versions of servers. Extract each offending binding to its own method, and override that method in a subclass:
public class ProductionModule extends AbstractModule {
protected void configure() {
bindLoginService();
bind(DataStore.class).to(MySqlDatabase.class);
bind(BillerConnection.class).to(SecureBillerConnection.class);
bind(LoggingEngine.class).to(DistributedLoggingEngine.class);
}
protected void bindLoginService() {
bind(LoginService.class).to(RemoteLoginService.class);
}
}

public class TestModule extends ProductionModule {
@Override protected void bindLoginService() {
bind(LoginService.class).to(FakeLoginService.class);
}
}

This does this trick, but it's not elegant. We end up with different subclasses for each combination of fake bindings. It's fragile and makes for more work to divide the module later.

New: overrideModule


Sam Berlin has contributed a feature to Guice that provides a simple mechanism to replace bindings. To use it, we create a module with binding overrides:
public class OverridesModule extends AbstractModule {
@Override protected void configure() {
bind(LoginService.class).to(FakeLoginService.class);
}
}

We can combine our original, unmodified ProductionModule with the overrides to create a third module:
    Module functionalTestModule 
= Guice.overrideModule(new ProductionModule(), new OverridesModule());

In this example, we get the DataStore, BillerConnection and LoggingEngine bindings from ProductionModule, but the FakeLoginService from OverridesModule. The bindings in the overriding module replace bindings of the same key from the production module.

It's not as clean as modular modules, but it is more convenient. In particular, this approach doesn't require changes to the production module - great if that's provided by another team or a third party. It's also handy for testing the module itself!

This code is in SVN now if you're interested. It uses the new commands API to get a lot done in a small amount of code.

Fair Warning: I've been blogging about a lot of new Guice APIs lately. These APIs aren't final. If you depend on unreleased APIs from Guice svn, be aware that those APIs will probably change for 2.0.