我有点问题。我认为这是一个典型的问题。但是,我找不到好的榜样。我的申请是使用泽西岛。我想通过客户端测试控制器作为测试。 Controller有私有字段 - StudentService。当我调试测试时,我看到,该字段为空。这会导致错误。我需要注入这个字段。我试过这个: 我的控制器
@Path("/student")
@Component
public class StudentResourse {
@Autowired
private StrudentService service; // this field Spring does not set
@Path("/getStudent/{id}")
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(@PathParam("id") long id) {
return service.get(id);
}
}
我的JUnit测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:config.xml")
@TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
@Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
@Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
@Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
@Test
@DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
我猜,这个问题出现在测试类中。因为,当我运行我的应用程序而不是测试时,我可以直接请求学生和一切正常工作。但是当我测试类时,Controller的内部字段没有设置。如何解决这个错误?谢谢你的回答。
这是我的config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
答案 0 :(得分:1)
一个问题可能是您尝试在构造函数和configure()
方法中配置测试应用程序。使用一个或另一个但不能同时使用两者,因为在这种情况下,您的configure()
方法不会被调用,因此您可能没有使用SpringServlet
以及此方法中定义的所有内容。
答案 1 :(得分:0)
参考:https://github.com/jiunjiunma/spring-jersey-test和http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
想法是通过使用ApplicationContextAware接口来获取运动衫内的应用程序上下文。之后,我们可以抓取spring之前已经创建的确切bean,在您的情况下为StudentService
。下面的示例显示了依赖项SampleService
的模拟版本,用于测试资源层api。
将处理委托给服务层的资源类
@Component
@Path("/sample")
public class SampleResource {
@Autowired
private SampleService sampleService;
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path ("/{id}")
public Sample getSample(@PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
封装业务逻辑的服务层
@Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
上述资源的单元测试
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
@Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use @ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
@Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
@Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
@Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
@Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
@Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
@Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
在jersey 1.8中使用以上内容