[英]How to unit test Jersey + Guice: ServiceLocator?
通過使用HK2的guice-bridge
我設法將Jersey 2.x與Guice 3.x集成在一起。
public class MyApp extends ResourceConfig {
@Inject
public MyApp(ServiceLocator serviceLocator) {
packages("com.mycompany");
...
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(GuiceContext.INJECTOR);
}
}
但現在我的澤西島測試不再適用了。
public abstract class AbstractJerseyTest extends JerseyTest {
public AbstractJerseyTest() throws TestContainerException {
super(new InMemoryTestContainerFactory());
}
protected Application configure() {
new MyApp(); // ERROR: missing 'ServiceLocator'
}
}
那么我在哪里可以獲得用於單元測試的ServiceLocator
?
也許更簡潔的方法是簡單地使用Feature
並在那里配置橋而不是在ResourceConfig
public class GuiceFeature implements Feature {
public void configure(FeatureContext context) {
ServiceLocator serviceLocator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(GuiceContext.INJECTOR);
}
}
這可以像任何其他功能一樣注冊。 只需register
它或使用@Provider
掃描它。
請注意, ServiceLocatorProvider
僅適用於Jersey 2.6及更高版本。
這是一個有效的解決方案。
關鍵是覆蓋JerseyTest的configureDeployment()方法並通過傳遞特定於Application的ResourceConfig.class而不是重寫configure()方法並返回ResourceConfig實例來創建DeploymentContext,以便測試容器正確初始化guice-bridge。
這是以下版本的Jersey,Guice和HK2 guice-bridge
<jersey.version>2.15</jersey.version>
<jackson2.version>2.4.4</jackson2.version>
<hk2.guice.bridge.version>2.4.0-b10</hk2.guice.bridge.version>
<guice.version>4.0-beta5</guice.version>
1)我的服務類
public interface MyService {
public void hello();
}
2)我的模擬服務Impl
public class MyMockServiceImpl implements MyService{
public void hello() {
System.out.println("Hi");
}
}
3)我的資源類與Guice注入服務
@Path("myapp")
public class MyResource {
private final MyService myService;
@Inject
public MyResource(MyService myService) {
this.myService = myService;
}
}
4)我的資源測試課程
public class MyResourceTest extends JerseyTestNg.ContainerPerClassTest {
@Override
protected Application configure() {
return null;
}
@Override
protected DeploymentContext configureDeployment() {
return DeploymentContext.builder(MyTestConfig.class).build();
}
// other test and setup/teardown methods
}
5)ResourceConfig類
static class MyTestConfig extends ResourceConfig {
@Inject
public MyTestConfig(ServiceLocator serviceLocator) {
packages("com.myapp.rest");
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(Guice.createInjector(new MyTestModule()));
}
}
6)我的Guice測試模塊課程
public class MyTestModule implements Module {
@Override
public void configure(Binder binder) {
binder.bind(MyService.class)
.to(MyMockServiceImpl.class);
}
}
注意:我之前從未使用過澤西島。 但是,您不應該再調用new MyApp()
; 否則Guice將無效。 相反,我可能嘗試這樣的事情:
public abstract class AbstractJerseyTest extends JerseyTest {
private final Module[] modules;
public AbstractJerseyTest(Module... modules) throws TestContainerException {
super(new InMemoryTestContainerFactory());
this.module = modules;
}
protected Application configure() {
Injector inj = Guice.createInjector(modules);
return inj.getInstance(MyApp.class);
}
}
public class ActualTest extends AbstractJerseyTest {
private static class TestModule extends AbstractModule {
@Override
public void configure() {
// Do your guice bindings here
}
}
public ActualTest() throws TestContainerException {
super(new TestModule());
}
}
我們在Groovy的幫助下工作:
public class MemoryTestContainerFactory implements TestContainerFactory {
private final Class<? extends Application> jaxrsApplicationClass;
public MemoryTestContainerFactory(Class<? extends Application> jaxrsApplicationClass) {
this.jaxrsApplicationClass = jaxrsApplicationClass;
}
@Override
public TestContainer create(URI baseUri, DeploymentContext context) throws IllegalArgumentException {
return new MemoryTestContainer(jaxrsApplicationClass, baseUri, context);
}
private static class MemoryTestContainer implements TestContainer {
private final URI baseUri;
private final ApplicationHandler appHandler;
private final AtomicBoolean started = new AtomicBoolean(false);
private static final Logger LOGGER = Logger.getLogger(MemoryTestContainer.class.getName());
MemoryTestContainer(Class<? extends Application> jaxrsApplicationClass, URI baseUri, DeploymentContext context) {
this.baseUri = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build();
this.appHandler = new ApplicationHandler(jaxrsApplicationClass);
}
@Override
public ClientConfig getClientConfig() {
def provider = new InMemoryConnector.Provider(baseUri, appHandler) // private access (only works with Groovy)
return new ClientConfig().connectorProvider(provider);
}
@Override
public URI getBaseUri() {
return baseUri;
}
@Override
public void start() {
if (started.compareAndSet(false, true)) {
LOGGER.log(Level.FINE, "Starting InMemoryContainer...");
} else {
LOGGER.log(Level.WARNING, "Ignoring start request - InMemoryTestContainer is already started.");
}
}
@Override
public void stop() {
if (started.compareAndSet(true, false)) {
LOGGER.log(Level.FINE, "Stopping InMemoryContainer...");
} else {
LOGGER.log(Level.WARNING, "Ignoring stop request - InMemoryTestContainer is already stopped.");
}
}
}
}
它不漂亮,但它的工作原理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.