如何从 JerseyTest 子类访问 Spring Bean
How to access Spring Bean from JerseyTest subclass
这是我的摘要 class,它以给定的 Spring 上下文开始 Jersey:
public abstract class AbstractJerseyTest extends JerseyTest {
public void setUp() throws Exception {
super.setUp();
}
@AfterClass
public void destroy() throws Exception {
tearDown();
}
@Override
protected URI getBaseUri() {
return URI.create("http://localhost:9993");
}
@Override
protected Application configure() {
RestApplication application = new RestApplication();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
properties.put("contextConfigLocation", "classpath:spring-context-test.xml");
application.setProperties(properties);
application.register(this);
return application;
}
}
所以,问题是我需要从我的测试中访问 Spring bean 以用一些数据填充数据库。
球衣版本为 2.6
我也发现了一个类似的问题here
但它与 Jersey 1.x 有关,因此它不适用于 Jersey 2.x
谁能指出我正确的方向?
通常在你的情况下,我只是说使用模拟工作,但在某些情况下你可能需要在测试中公开服务 class。
要在没有任何“丑陋的技巧”的情况下做到这一点,您需要掌握 ServiceLocator
(类似于 Spring 的 ApplicationContext
)。当 Jersey 应用程序启动时,来自 ApplicationContext
的所有 Spring 服务都通过 HK2 的 Spring 桥放入 ServiceLocator
。
问题是 JerseyTest
没有以任何方式公开 ServiceLocator
。我能想到的唯一方法是创建你自己的 TestContainerFactory
,并创建 ApplicationHandler
,它公开了 ServiceLocator
.
尝试实现自己的 TestContainerFactory
不是在公园散步,如果您不知道自己在做什么。最简单的做法就是查看 Jersey InMemoryTestContainerFactory
的源代码。如果您查看内部 class InMemoryTestContainer
的构造函数,您会看到它创建了 ApplicationHandler
。这就是通过 appHandler.getServiceLocator()
.
公开 ServiceLocator
的方法
因此,如果您复制 class,并公开 ServiceLocator
,您可以创建 JerseyTest
扩展,并调用 ServiceLocator.inject(Object)
方法来注入测试 class.
public abstract class AbstractServiceLocatorAwareJerseyTest extends JerseyTest {
private final ServiceLocatorAwareInMemoryTestContainerFactory factory
= new ServiceLocatorAwareInMemoryTestContainerFactory();
private ServiceLocator locator;
@Override
public TestContainerFactory getTestContainerFactory() {
return factory;
}
@Before
@Override
public void setUp() throws Exception {
super.setUp();
this.locator = factory.getServiceLocator();
if (injectTestClass()) {
this.locator.inject(this);
}
}
public boolean injectTestClass() {
return true;
}
public ServiceLocator getServiceLocator() {
return locator;
}
}
如果出于任何原因您需要它,ServiceLocator
也有 ApplicationContext
,如果需要,您也可以将其公开给您的测试 class。
我整理了一份 GitHub project,其中包含完整的实现和测试,如果你想看一下的话。
更新
尽管 OP 对这个问题的回答有效,但我认为它有效的事实是一个错误。我最初删除了这个答案,在 OP post 编辑了他们的答案之后,但经过一些测试,我认为这个解决方案是一个错误,所以我为任何不喜欢的人取消删除这个 post warning1 你在使用那个解决方案时得到
1. “警告:在 SERVER 运行时中注册的提供者 SimpleTest 未实现适用于 SERVER 运行时的任何提供者接口。由于约束配置问题,提供者 SimpleTest 将被忽略。”
解决方法非常简单。
我补充说:
@Autowired
private Repository repository;
到 AbstractJerseyTest 并且该字段在测试启动期间自动连接。我不知道它是如何工作的细节,但似乎当我在 REST 应用程序中注册测试实例时
application.register(this);
它会自动装配测试中的所有 bean。
这是我的摘要 class,它以给定的 Spring 上下文开始 Jersey:
public abstract class AbstractJerseyTest extends JerseyTest {
public void setUp() throws Exception {
super.setUp();
}
@AfterClass
public void destroy() throws Exception {
tearDown();
}
@Override
protected URI getBaseUri() {
return URI.create("http://localhost:9993");
}
@Override
protected Application configure() {
RestApplication application = new RestApplication();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
properties.put("contextConfigLocation", "classpath:spring-context-test.xml");
application.setProperties(properties);
application.register(this);
return application;
}
}
所以,问题是我需要从我的测试中访问 Spring bean 以用一些数据填充数据库。
球衣版本为 2.6
我也发现了一个类似的问题here
但它与 Jersey 1.x 有关,因此它不适用于 Jersey 2.x
谁能指出我正确的方向?
通常在你的情况下,我只是说使用模拟工作,但在某些情况下你可能需要在测试中公开服务 class。
要在没有任何“丑陋的技巧”的情况下做到这一点,您需要掌握 ServiceLocator
(类似于 Spring 的 ApplicationContext
)。当 Jersey 应用程序启动时,来自 ApplicationContext
的所有 Spring 服务都通过 HK2 的 Spring 桥放入 ServiceLocator
。
问题是 JerseyTest
没有以任何方式公开 ServiceLocator
。我能想到的唯一方法是创建你自己的 TestContainerFactory
,并创建 ApplicationHandler
,它公开了 ServiceLocator
.
尝试实现自己的 TestContainerFactory
不是在公园散步,如果您不知道自己在做什么。最简单的做法就是查看 Jersey InMemoryTestContainerFactory
的源代码。如果您查看内部 class InMemoryTestContainer
的构造函数,您会看到它创建了 ApplicationHandler
。这就是通过 appHandler.getServiceLocator()
.
ServiceLocator
的方法
因此,如果您复制 class,并公开 ServiceLocator
,您可以创建 JerseyTest
扩展,并调用 ServiceLocator.inject(Object)
方法来注入测试 class.
public abstract class AbstractServiceLocatorAwareJerseyTest extends JerseyTest {
private final ServiceLocatorAwareInMemoryTestContainerFactory factory
= new ServiceLocatorAwareInMemoryTestContainerFactory();
private ServiceLocator locator;
@Override
public TestContainerFactory getTestContainerFactory() {
return factory;
}
@Before
@Override
public void setUp() throws Exception {
super.setUp();
this.locator = factory.getServiceLocator();
if (injectTestClass()) {
this.locator.inject(this);
}
}
public boolean injectTestClass() {
return true;
}
public ServiceLocator getServiceLocator() {
return locator;
}
}
如果出于任何原因您需要它,ServiceLocator
也有 ApplicationContext
,如果需要,您也可以将其公开给您的测试 class。
我整理了一份 GitHub project,其中包含完整的实现和测试,如果你想看一下的话。
更新
尽管 OP 对这个问题的回答有效,但我认为它有效的事实是一个错误。我最初删除了这个答案,在 OP post 编辑了他们的答案之后,但经过一些测试,我认为这个解决方案是一个错误,所以我为任何不喜欢的人取消删除这个 post warning1 你在使用那个解决方案时得到
1. “警告:在 SERVER 运行时中注册的提供者 SimpleTest 未实现适用于 SERVER 运行时的任何提供者接口。由于约束配置问题,提供者 SimpleTest 将被忽略。”
解决方法非常简单。 我补充说:
@Autowired
private Repository repository;
到 AbstractJerseyTest 并且该字段在测试启动期间自动连接。我不知道它是如何工作的细节,但似乎当我在 REST 应用程序中注册测试实例时
application.register(this);
它会自动装配测试中的所有 bean。