dong
dong

Reputation: 701

how to handle multi-layered injection using Guice

I am now using Guice for JUnit test for JSF web application. Suppose I have several classes:

class ServiceA
{
   @Inject
   ServiceB serviceB;
   //do something using serviceB
   ...
}

interface ServiceB
{
//APIs in ServiceB
...
}

class ServiceBImpl implements ServiceB
{
   @Inject
   ServiceC serviceC;
   //do something using serviceC
   ...
}

interface ServiceC
{
//APIs in ServiceC
...
}

class ServiceCImpl implements ServiceC
{
   //do something
   ...
}

Now I use Guice to build a module for ServiceA. My module would look like the following

class ServiceAModule implements Module
{
    @Override
    public void configure(Binder binder) {
    binder.bind(ServiceB.class).to(ServiceBImpl.class);
    }
}

And in my JUnit test class, I use Guice to create Injection, which looks like :

public ServiceATest
{

    ServiceA serviceA;

    @Before
    public void before()
    {
       Injector injector = Guice.createInjector(new ServiceAModule());
       serviceA = injector.getInstance(ServiceA.class);
    }

    //do the test
    ...
}

Now the problem is the ServiceATest knows nothing about "ServiceC", and it will not be injected into ServiceB.

Of course I can build another module to introduce ServiceC's injection in ServiceB. But this surely break the code layering. What if ServiceC is developed by another person and I know nothing about ServiceC? this should not be a good solution.

Is it possbile for Guice to handle such multi-layered injection?

Upvotes: 0

Views: 623

Answers (1)

kan
kan

Reputation: 28991

You should not do multi-layered injection unless you are doing an integration test.

In a unit test ServiceATest you should inject ServiceB mock and don't care about ServiceC and guice modules. You could just use mockito's @InjectMocks instead of Guice.

If you are doing an integration test, then you should decide which components are involved in a particular test. All components which are outside of the test scope you should mock, probably you would use additional ad-hock MockModule right inside the test case to bind mocked dependencies.

BTW, instead of using getInstance you could inject beans inside your unit test, i.e.:

public ServiceATest
{
    @Inject
    ServiceA serviceA;

    @Before
    public void before()
    {
       Injector injector = Guice.createInjector(new ServiceAModule());
       injector.injectMembers(this);
    }
}

Upvotes: 2

Related Questions