Jersey 2单元测试中注入依赖项

4
我有一个像这样的控制器。
@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());

我的DIBinder中包含了所有的绑定(例如

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

现在我想为这个控制器编写一个单元测试,是否可能将整个AccountController实例及其所有传递依赖项注入测试中?
类似以下内容:
    @Inject
    AccountController accountController;
2个回答

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);
    }
}

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();
        }
    }
}

然后在你的具体类中

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());
    }
}

如果您再花些时间,我相信您可以设计出更好的抽象测试类。这是我想到的第一件事。
注意:对于任何请求范围内的内容,您可能需要模拟它。在运行单元测试时,没有请求上下文,因此测试将失败。
另请参阅:
- 在独立应用程序中使用Jersey的依赖注入 - HK2文档

1
谢谢你的回答!什么是TestBinder? - andreybavt
这是我用来测试示例的绑定器。它只包含了一个简单的服务绑定。对于你来说,它将是MyDIBinding。 - Paul Samsotha
5
@peeskillet,请使用一个 TestBinder 的例子来完善这个回答。 - 4F2E4A2E

0
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;

@BeforeClass
    public static void doTest() {
        ServiceLocator serviceLocator = ServiceLocatorUtilities.bind(new AbstractBinder() {
            @Override
            protected void configure() {
                bindAsContract(YourClass1.class);
                bindAsContract(YourClass2.class);
                bindAsContract(YourClass3.class);
            }
        });

        YourClass1 yourClass1 = serviceLocator.getService(YourClass1.class);
        ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接