RHLab
RHLab

Reputation: 23

Guice: Different bindings in test and subproject

I have a maven project javaruntime and a maven project androidruntime which depends on the javaruntime project. Each of the projects has a Guice-Module binding some classes to Interfaces.

In the javaruntime is an Interface IElementFactory and a Class C which gets the IElementFactory by constructor injection:

public class C {
    @Inject
    public C(IElementFactory factory, ...(other interfaces)...) {...}
    // ...
}

The concrete Implementation for the IElementFactory is in the androidruntime project and called AndroidElementFactory. All implementations of the other interfaces are within the javaruntime.

In the javaruntime I have JUnit-tests which should use a MockElementFactory because it does not know the androidruntime.

If I bind the IElementFactrory to the AndroidElementFactory only in the androidruntime Module, the Tests fail of course, because no implementation is bound for that interface within the javaruntime Module/project.

If I then bind the MockElementFactory in the javaruntime Module the tests are fine, but then I cannot compile the androidruntime because the IElementFactory is already bound to the MockElementFactory and overriding a binding is bad and not reommended in Guice.

But how can I accomplish that the Mock is used for the test and in the android-project it is still possible to bind the correct implementation?

Upvotes: 2

Views: 2491

Answers (1)

Vladimir Matveev
Vladimir Matveev

Reputation: 127771

First of all, in fact you don't want to do that. When you're unit testing your class, especially with mocks, you shouldn't use Guice. Instead you should instantiate your class directly, providing all its dependencies to it. Since you're writing unit test this should not be a problem, since all its dependencies in the test should be trivial or be mocked.

But if you really want to do what you intend to do, you have to split your program into several modules. For simplicity, let them be MainModule, MockModule and AndroidModule. In MainModule you configure all your bindings except for IElementFactory. It can look like this:

public class MainModule extends AbstractModule {
    @Override
    protected void configure() {
        // Require presence of IElementFactory
        requireBinding(IElementFactory.class);

        // Bind all other dependencies
        ...
    }
}

And in your MockModule and AndroidModule you bind corresponding implementations of IElementFactory.

Then in your tests you create your injector like this:

Injector injector = Guice.createInjector(new MainModule(), new MockModule());

and in android project you create it like this:

Injector injector = Guice.createInjector(new MainModule(), new AndroidModule());

If you cannot do this because injector instantiation is hardcoded, then you should really consider refactoring your program because it is not how Guice projects are structured, especially wrt. unit tests. I cannot say more because you haven't explained exact structure of your program.

Upvotes: 6

Related Questions