@Context 在集成测试期间为 null
@Context is null during integration test
我在休息应用程序上使用 spring boot 1.3.0。我正在尝试使用 RestAssured 创建集成测试。我在@Context 上遇到问题。它没有被注入控制器以供我获取 URI。
这是测试 class:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebIntegrationTest("server.port=8080")
@ActiveProfiles(value = {"testing"})
public class InvoiceRestServiceIT {
private static String INVOICE_DATA = "<invoice data>";
private static String INVOICE_URL = "/customers/1q2w3e4r/invoices";
@Test
public void testPostInvoice() {
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body(INVOICE_DATA)
.expect()
.statusCode(200)
.body(containsString("entity"), containsString("id"))
.when()
.post(INVOICE_URL);;
}
}
这是服务 class(InvoiceRestService.java):
@Autowired
private InvoiceController invoiceController;
@POST
public EntityResponse add(InvoiceResource invoiceResource) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource));
}
这是控制器(扩展 RestController 的 InvoiceController):
protected Customer getCustomer() {
Customer customer = customerRepository.findOne(getCustomerId());
...
}
这里是错误发生的地方(RestController.java):
@Context
private HttpServletRequest request;
protected String getCustomerStringId() {
Matcher matcher = pattern.matcher(request.getRequestURI()); //<---- Here, request object is null
if (!matcher.find()) {
throw new IllegalStateException("Cannot find customer id in request URL");
}
return matcher.group(1);
}
这是错误日志:
java.lang.NullPointerException: null
at org.store.rest.RestController.getCustomer(RestController.java:90)
at org.store.rest.invoice.InvoiceController.createInvoice(InvoiceController.java:87)
at org.store.rest.invoice.InvoiceController$$FastClassBySpringCGLIB$d6c1a2e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.store.rest.invoice.InvoiceController$$EnhancerBySpringCGLIB$cabdc3.createInvoice(<generated>)
at com.store.rest.invoice.InvoiceRestService.add(InvoiceRestService.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497
有人遇到过吗?如何解决这个问题?
从 REST Assured 2.2 开始,您可以使用 RestAssuredMockMvc from the spring-mock-mvc 模块并避免启动网络服务器来进行测试。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = Application.class,
loader = AnnotationConfigWebContextLoader.class)
public class ApplicationTest {
@Autowired
private WebApplicationContext wac;
@Before
public void setUp() {
RestAssuredMockMvc.webAppContextSetup(wac);
}
@Test
public void test() {
// your REST Assured test for any controller
}
}
对请求使用@Autowired
注解
@Autowired
private HttpServletRequest request;
看来您的 控制器 更像是实用程序 类 而您的 服务 实际上是一个控制器。因此,在这方面,您的 InvoiceController
可能不是 JAX RS 根资源。
我认为最简单的解决方案(如果你想继续沿着这条路走)是删除 RestController
中的 @Context private HttpServletRequest request;
声明并将其移动到 InvoiceRestService
,如下所示:
@POST
public EntityResponse add(InvoiceResource invoiceResource, @Context HttpServletRequest request) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource, request));
}
然后您需要将 request
传递给您的 InvoiceController
实用程序。
但是...最优雅的解决方案是让 JAX RS 从传入路径中解析 ID。使用 @Path
,您可以为路径的命名段定义占位符,并将这些段注入到您的 JAX RS 端点方法中,如下所示:
@Path("/customers/{customerId}/invoices")
public class InvoiceRestService {
@POST
public EntityResponse add(@PathParam("customerId") String customerId, InvoiceResource invoiceResource) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource, customerId));
}
}
我在休息应用程序上使用 spring boot 1.3.0。我正在尝试使用 RestAssured 创建集成测试。我在@Context 上遇到问题。它没有被注入控制器以供我获取 URI。
这是测试 class:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebIntegrationTest("server.port=8080")
@ActiveProfiles(value = {"testing"})
public class InvoiceRestServiceIT {
private static String INVOICE_DATA = "<invoice data>";
private static String INVOICE_URL = "/customers/1q2w3e4r/invoices";
@Test
public void testPostInvoice() {
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body(INVOICE_DATA)
.expect()
.statusCode(200)
.body(containsString("entity"), containsString("id"))
.when()
.post(INVOICE_URL);;
}
}
这是服务 class(InvoiceRestService.java):
@Autowired
private InvoiceController invoiceController;
@POST
public EntityResponse add(InvoiceResource invoiceResource) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource));
}
这是控制器(扩展 RestController 的 InvoiceController):
protected Customer getCustomer() {
Customer customer = customerRepository.findOne(getCustomerId());
...
}
这里是错误发生的地方(RestController.java):
@Context
private HttpServletRequest request;
protected String getCustomerStringId() {
Matcher matcher = pattern.matcher(request.getRequestURI()); //<---- Here, request object is null
if (!matcher.find()) {
throw new IllegalStateException("Cannot find customer id in request URL");
}
return matcher.group(1);
}
这是错误日志:
java.lang.NullPointerException: null
at org.store.rest.RestController.getCustomer(RestController.java:90)
at org.store.rest.invoice.InvoiceController.createInvoice(InvoiceController.java:87)
at org.store.rest.invoice.InvoiceController$$FastClassBySpringCGLIB$d6c1a2e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.store.rest.invoice.InvoiceController$$EnhancerBySpringCGLIB$cabdc3.createInvoice(<generated>)
at com.store.rest.invoice.InvoiceRestService.add(InvoiceRestService.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497
有人遇到过吗?如何解决这个问题?
从 REST Assured 2.2 开始,您可以使用 RestAssuredMockMvc from the spring-mock-mvc 模块并避免启动网络服务器来进行测试。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = Application.class,
loader = AnnotationConfigWebContextLoader.class)
public class ApplicationTest {
@Autowired
private WebApplicationContext wac;
@Before
public void setUp() {
RestAssuredMockMvc.webAppContextSetup(wac);
}
@Test
public void test() {
// your REST Assured test for any controller
}
}
对请求使用@Autowired
注解
@Autowired
private HttpServletRequest request;
看来您的 控制器 更像是实用程序 类 而您的 服务 实际上是一个控制器。因此,在这方面,您的 InvoiceController
可能不是 JAX RS 根资源。
我认为最简单的解决方案(如果你想继续沿着这条路走)是删除 RestController
中的 @Context private HttpServletRequest request;
声明并将其移动到 InvoiceRestService
,如下所示:
@POST
public EntityResponse add(InvoiceResource invoiceResource, @Context HttpServletRequest request) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource, request));
}
然后您需要将 request
传递给您的 InvoiceController
实用程序。
但是...最优雅的解决方案是让 JAX RS 从传入路径中解析 ID。使用 @Path
,您可以为路径的命名段定义占位符,并将这些段注入到您的 JAX RS 端点方法中,如下所示:
@Path("/customers/{customerId}/invoices")
public class InvoiceRestService {
@POST
public EntityResponse add(@PathParam("customerId") String customerId, InvoiceResource invoiceResource) {
return new EntityResponse(invoiceController.createInvoice(invoiceResource, customerId));
}
}