Let me try first a quick answer, then we can iterate over details if you'd like.
The use of Modules.override() here is what gives the ability to mock a set of components that effectively represent interfaces to those components from a system. For example, if you have something like:
class MakesRpcCalls {
@Inject MakesRpcCalls(
RpcInterface rpcInterface) {
...
}
RpcResponse makeRpc(RpcRequest rpcRequest) {
... do some stuff
return rpcInterface.call(rpcRequest);
}
}
You might want to mock RpcInterface in your test.
Imagine the module that binds this interface in production looks like:
public class RealRpcInterfaceModule extends AbstractModule {
@Override protected void configure() {
bind(RpcInterface.class).to(RealBackendServiceInterface.class);
...
}
}
And your application module might then install it:
public class ApplicationModule extends AbstractModule {
@Override protected void configure() {
install(new RealRpcInterfaceModule());
....
}
}
And your main() method might look like:
public static void main(String[] args) {
Injector injector = Guice.createInjector(new ApplicationModule());
Server server = injector.getInstance(Server.class);
server.runForever();
}
In an integration test, you'd want to be able to do something like start this server pointing at a mock rpc backend. One way to do this is to add another method:
public static void main(String[] args) {
// imagine 'EmptyModule' is one with no bindings. thus, by default,
// don't override any bindings within 'ApplicationModule'
programmaticMain(args, new EmptyModule());
}
/**
* Accepts the args from the command line and an {@code overrideModule}, the
* bindings in which are used to override bindings in the {@link ApplicationModule}.
*/
public static void programmaticMain(String[] args, Module overrideModule) {
Module moduleToUse = Modules.override(new ApplicationModule)).with(overrideModule);
Injector injector = Guice.createInjector(moduleTouse);
Server server = injector.getInstance(Server.class);
server.runForever();
}
In your integration test, you'd then start a server with:
Server.programmaticMain(<args>, new AbstractModule() {
@Override protected void configure() {
bind(RpcInterface.class).to(MockedOutRpcInterface.class);
}
}
Of course many variations on this theme exist, but the gist of overriding production bindings remains the same.
Fred