5

I have some service which uses an Java EE ManagedExecutorService (in Wildfly 9)

public class FooService{
    @Resource
    ManagedExecutorService executorService;
}

For a test with Mockito, I would like to use a "normal" ExecutorService

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest{
   @Spy
   ManagedExecutorService executorService = Executors.newFixedThreadPool(5);
}

This code obviously does not compile, as an ExecutorService is not a ManagedExecutorService.

When using an ExecutorService in the service, the test runs without errors, but then Wildfly cannot inject the service.

public class FooService{
    @Resource
    ExecutorService executorService;
}

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
   @Spy
   ExecutorService executorService = Executors.newFixedThreadPool(5);
}

It would be possible to create a ManagedExecutorService by delegating to a ExecutorService:

@Spy
ManagedExecutorService executorService = new ManagedExecutorService() {

   ExecutorService executorService = Executors.newFixedThreadPool(5);
   @Override
   public void shutdown() {
       executorService.shutdown();
   }

   // delegate for all (12) methods
}

Is there a simpler way to use an ExecutorService in the test without changing the service which runs in Wildfly?

user140547
  • 7,750
  • 3
  • 28
  • 80
  • Why do you need a non-mock instance of `ManagedExecutorService`? That's an interface which can easily be mocked. – SpaceTrucker Jun 10 '16 at 13:00
  • @SpaceTrucker: Well it is not a unit test, so the tasks submitted to the ExecutorService should actually run. It would be possible to use Arquillian, but I thought it may be simpler to just use an Java SE ExecutorService. – user140547 Jun 10 '16 at 13:15
  • Then why not use a mock that runs the submitted tasks? Just implement Answer accordingly http://site.mockito.org/mockito/docs/current/org/mockito/stubbing/Answer.html – SpaceTrucker Jun 10 '16 at 13:39
  • @SpaceTrucker: Well for simple Runnables this is possible but if the service uses the Future returned by saying submit, it gets complicated, does it not? – user140547 Jun 10 '16 at 14:06
  • I think you need to rethink the scope of the test. If the scope is to actually run the tasks within the environment provided by a `ManagedExecutorService` than you actually need to provide it and make this test using a cleanly started container. – SpaceTrucker Jun 10 '16 at 16:13

1 Answers1

0

I use injection pattern:

class DefaultImpl {
 static DefaultFactory me;
 static DefaultFactory getCurrentInstance()
  { if (me == null) {
     me = new DefaultFactory();
    }
    return me;
  }
void setCurrentInstance(DefaultFactory df){
  me = df;
}
 ExecutorService getExecutorService(){
   // lookup and return ManagedExecutorService
 }
}
class TestImpl extends DefaultImpl{
  TestImpl(){
    DefaultFactory.setCurrentInstance(this); <-- this now sets your TestImpl for any call
  }
  ExecutorService getExecutorService(){
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    return executorService;
  }
}

//junit
@Test
void someTest(){
 new TestImpl();
 // do something all your calls will use non managed executor service
}

You can also call new TestImpl() from junit setup(). Also if you want to make it more flexible then you can have a BaseImpl and have both DefaultImpl and TestImpl extend it.

Hope this helps!

donlys
  • 440
  • 6
  • 13