Jersey 2将依赖注入单元测试

and*_*avt 3 java unit-testing dependency-injection jersey jersey-2.0

我有这样的控制器

@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;
    }
...
Run Code Online (Sandbox Code Playgroud)

我正在使用注入AccountDao和AccountService

ResourceConfig config = new ResourceConfig()
               .packages("controller", "exception")
               .register(new MyDIBinder());
Run Code Online (Sandbox Code Playgroud)

MyDIBinder包含所有绑定的地方(例如

AccountDaoImpl accountDaoImpl = new AccountDaoImpl();
bind(accountDaoImpl).to(AccountDao.class);
Run Code Online (Sandbox Code Playgroud)

)

现在我想为这个控制器编写一个单元测试,是否可以将整个AccountController实例及其所有传递依赖项注入测试?

就像是

    @Inject
    AccountController accountController;
Run Code Online (Sandbox Code Playgroud)

Pau*_*tha 5

您可以使用主IoC容器,只需显式注入测试类.Jersey使用HK2作为其DI框架,其IoC容器是ServiceLocator,它有一个方法inject(anyObject)可以注入任何具有其注册表中的依赖项的对象.

例如,你可以做类似的事情

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

ServiceLocatorUtilities班是一个辅助类,使我们能够轻松地创建ServiceLocator,然后我们只需要调用inject(this)注入InjectionTest.

如果对所有控制器测试执行此操作似乎重复,则可能需要创建一个抽象基础测试类.也许是这样的

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的具体课堂上

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你花了一些时间,我相信你可以想出一个更好的抽象测试类设计.这是我想到的第一件事.

注意:对于任何请求作用域,您可能只需要模拟它.运行单元测试时,没有请求上下文,因此测试将失败.

也可以看看:

  • @peeskillet 请使用 TestBinder 示例完成此回复。 (2认同)