Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey 2 inject dependencies into unit test

I have a controller like this

@Path("/")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AccountController implements CRUDController<Long, Account> {

    private AccountDao accountDao;
    private AccountService accountService;

    @Inject
    public AccountController(AccountDao accountDao, AccountService accountService) {
        this.accountDao = accountDao;
        this.accountService = accountService;
    }
...

I'm injecting AccountDao and AccountService using

ResourceConfig config = new ResourceConfig()
               .packages("controller", "exception")
               .register(new MyDIBinder());

Where MyDIBinder is contains all the bindings (e.g

AccountDaoImpl accountDaoImpl = new AccountDaoImpl();
bind(accountDaoImpl).to(AccountDao.class);

)

Now I want to write a unit test for this controller, is it possible to inject the whole AccountController instance with all of it's transitive dependencies into the test?

Something like

    @Inject
    AccountController accountController;
like image 959
andreybavt Avatar asked Oct 17 '25 19:10

andreybavt


1 Answers

You can use the main IoC container, and just explicitly inject the test class. Jersey uses HK2 as its DI framework, and its IoC container is the ServiceLocator, which has a method inject(anyObject) that can inject any objects with dependencies that are in its registry.

For example you could do something like

public class InjectionTest {

    @Inject
    private TestController controller;

    @Before
    public void setUp() {
        final Binder b = new AbstractBinder() {
            @Override
            public void configure() {
                bindAsContract(TestController.class);
            }
        };
        final ServiceLocator locator = ServiceLocatorUtilities.bind(new TestBinder(), b);
        locator.inject(this);
    }

    @Test
    public void doTest() {
        assertNotNull(controller);
        String response = controller.get();
        assertEquals("Hello Tests", response);
    }
}

The ServiceLocatorUtilities class is a helper class that allows us to easily create the ServiceLocator, and then we just call inject(this) to inject the InjectionTest.

If it seems repetitive to do this for all your controller tests, you may want to create an abstract base test class. Maybe something like

public abstract class AbstractControllerTest {

    protected ServiceLocator locator;
    private final Class<?> controllerClass;

    protected AbstractControllerTest(Class<?> controllerClass) {
        this.controllerClass = controllerClass;
    }

    @Before
    public void setUp() {
        final AbstractBinder binder = new AbstractBinder() {
            @Override
            public void configure() {
                bindAsContract(controllerClass);
            }
        };
        locator = ServiceLocatorUtilities.bind(new TestBinder(), binder);
        locator.inject(this);
    }

    @After
    public void tearDown() {
        if (locator != null) {
            locator.shutdown();
        }
    }
}

Then in your concrete class

public class TestControllerTest extends AbstractControllerTest {

    public TestControllerTest() {
        super(TestController.class);
    }

    @Inject
    private TestController controller;

    @Test
    public void doTest() {
        assertNotNull(controller);
        assertEquals("Hello Tests", controller.get());
    }
}

If you spent some more time, I'm sure you could come up with a better abstract test class design. It was the first thing that came to mind for me.

Note: For anything request scoped, you mayb need to just mock it. When running the unit tests, there is no request context, so the test will fail.

See Also:

  • Using Jersey's Dependency Injection in a Standalone application
  • HK2 documentation
like image 71
Paul Samsotha Avatar answered Oct 20 '25 07:10

Paul Samsotha