Integration Testing, Mocking

1,452 views
Skip to first unread message

Nathandelane

unread,
Aug 18, 2011, 12:13:01 PM8/18/11
to google-guice
For a long time I have been working on a series of automated tests
that rely on the creation of mocks through a service lookup utility
(like Spring framework's), which in some ways resembles a dependency
injection framework and is used like a DI framework, but it doesn't
quite work the same way, and it has some intricacies that make it less
reliable for DI in my opinion. Recently I've been trying to implement
the usage of Guice in place of this service lookup utility, and I've
been running into a possible issue that I can't seem to figure out. I
however suppose that I must be missing something in relation to Guice.

Essentially there are cases when we mock portions of a system and set
them up in advance of running that system. Our service lookup utility
in this sense seems to be global. In Guice however there seems to be a
requirement of concrete implementations of AbstractModule or more
correctly the Module interface. It seems to me that all of the
examples provided use those implementations explicitly right before
requesting an instance of an interface in question. If this is the
case, then how would I implement my integration tests using Guice to
mock certain portions of a system in advance of calling that system,
and ensure that my mocks (in a Module implementation) get used? There
isn't any way to do this is there? Because Guice isn't global, or
rather the bindings aren't global to the test application or
application under test, rather they are local.

This is probably a special situation. Can anybody please help me
clarify this point?

Thanks.

Nathan Lane

Fred Faber

unread,
Aug 18, 2011, 2:43:36 PM8/18/11
to google...@googlegroups.com
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


--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.


Nathandelane

unread,
Aug 18, 2011, 5:16:58 PM8/18/11
to google-guice
Thanks you for taking the time to respond. Let me see if I understand
you basically correctly. It appears as though you are using
Modules.override(...).with(...) to ensure that a mock module is
utilized. Is that correct?

Fred Faber

unread,
Aug 18, 2011, 10:46:32 PM8/18/11
to google...@googlegroups.com
Basically, yes.  Ideally you'd retain as many "real" bindings as possible, as to test most of the production aspects of your system.  The mock bindings would override some of these real bindings to do things like stub out backends.  
Reply all
Reply to author
Forward
0 new messages