Search code examples
junitguicejmockit

JMockit + Guice: can @Tested and Guice mix in the same test class?


I'm trying to use JMockit and Guice and found a non-trivial behaviour. I have this class:

public class BusinessService {
  PersistenceService mPS;
  StockService mSS;

  @Inject
  public BusinessService(PersistenceService ps, StockService ss) {
    mPS = ps;
    mSS = ss;
  }
...
}

The dependency on PersistenceService and StockService is managed with Guice. I have tried these two test together in the same test class:

public class Test_BusinessService_all {
  @Tested
  BusinessService bs;

  @Test
  public void test_buy_allmock(@Injectable final StockService ss,
                               @Injectable final PersistenceService ps) {
    Operation o = bs.buy("NVDA", 10000);
  }

  @Test
  public void test_buy() throws StockNotFound, InvalidOperation {
    Injector injector = Guice.createInjector(new USAModule());
    bs = injector.getInstance(BusinessService.class);

    Operation o = bs.buy("NVDA", 10000);
  }
}

But the second one raises an exception:

java.lang.IllegalArgumentException: No constructor in class org.udg.caes.exercici3.BusinessService that can be satisfied by available injectables
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

But if I separate the two test into two test classes, both work!. In the second test class (guice version) I don't use @Tested so, is @Tested somehow interfering with Guice ? What am I missing ?

Thanks


Solution

  • Yes the problem is caused by @Tested. As @Tested is declared in this test file, then JMockit needs to find @Injectables to satisfy it's available constructors, for each test method. This is not possible for the 'test_buy' method. So moving the test 'test_buy' into another test class will work if the new test class has no @Tested 'BusinessService' field.

    In 'test_buy' you are not using the @Tested field so you could either separate the tests, as you have already done, or rewrite the tests so that they can follow the same approach.

    See http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Tested.html