Jersey 2 将依赖项注入单元测试
Jersey 2 inject dependencies into unit test
我有一个这样的控制器
@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;
}
...
我正在使用
注入 AccountDao 和 AccountService
ResourceConfig config = new ResourceConfig()
.packages("controller", "exception")
.register(new MyDIBinder());
MyDIBinder 包含所有绑定(例如
AccountDaoImpl accountDaoImpl = new AccountDaoImpl();
bind(accountDaoImpl).to(AccountDao.class);
)
现在我想为这个控制器编写一个单元测试,是否可以将整个 AccountController 实例及其所有传递依赖项注入到测试中?
类似于
@Inject
AccountController accountController;
您可以使用主 IoC 容器,并直接注入测试 class。 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);
}
}
ServiceLocatorUtilities
class 是一个帮助程序 class ,它允许我们轻松创建 ServiceLocator
,然后我们只需调用 inject(this)
来注入InjectionTest
.
如果对所有控制器测试执行此操作似乎重复,您可能需要创建一个抽象基础测试 class。也许像
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();
}
}
}
然后在你的具体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());
}
}
如果您多花点时间,我相信您可以想出更好的抽象测试 class 设计。这是我想到的第一件事。
注意:对于范围内的任何请求,您可能只需要模拟它。 运行 unit 测试时,没有请求上下文,所以测试会失败。
另请参阅:
我有一个这样的控制器
@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;
}
...
我正在使用
注入 AccountDao 和 AccountServiceResourceConfig config = new ResourceConfig()
.packages("controller", "exception")
.register(new MyDIBinder());
MyDIBinder 包含所有绑定(例如
AccountDaoImpl accountDaoImpl = new AccountDaoImpl();
bind(accountDaoImpl).to(AccountDao.class);
)
现在我想为这个控制器编写一个单元测试,是否可以将整个 AccountController 实例及其所有传递依赖项注入到测试中?
类似于
@Inject
AccountController accountController;
您可以使用主 IoC 容器,并直接注入测试 class。 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);
}
}
ServiceLocatorUtilities
class 是一个帮助程序 class ,它允许我们轻松创建 ServiceLocator
,然后我们只需调用 inject(this)
来注入InjectionTest
.
如果对所有控制器测试执行此操作似乎重复,您可能需要创建一个抽象基础测试 class。也许像
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();
}
}
}
然后在你的具体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());
}
}
如果您多花点时间,我相信您可以想出更好的抽象测试 class 设计。这是我想到的第一件事。
注意:对于范围内的任何请求,您可能只需要模拟它。 运行 unit 测试时,没有请求上下文,所以测试会失败。
另请参阅: