使用RestAssured编写POST接口JUnit测试时遇NoHttpResponseException问题
解决RestAssured POST测试中
org.apache.http.NoHttpResponseException异常 我来帮你排查这个问题,你遇到的org.apache.http.NoHttpResponseException本质是RestAssured向localhost:8080发送请求后,没有收到任何响应——大概率是你的Mock服务器没正确处理请求,或者请求本身存在配置问题,咱们一步步来解决:
1. 先确认MockRESTServer的有效性
你用的MockRESTServer看起来是自定义的Mock服务器,首先要确保它真的在8080端口正常启动,并且能正确路由/create的POST请求:
- 可以先跳过RestAssured,直接用
curl命令测试Mock服务器:
如果curl也返回无响应,那问题出在Mock服务器本身,检查它的启动逻辑、路由映射是否正确,比如是否真的把curl -X POST -H "Content-Type: application/json" -d '{"name":"policy123"}' http://localhost:8080/createPolicyResource绑定到了根路径。
2. 显式配置RestAssured的基础地址
虽然你代码里的请求路径看起来没问题,但显式指定base URI和端口能避免默认配置的潜在问题,修改测试代码:
@Test public final void testCreatePolicy() { // 显式设置基础地址 RestAssured.baseURI = "http://localhost"; RestAssured.port = 8080; Policy policy=new Policy(); policy.setName("policy123"); RestAssured.with() .contentType("application/json") .accept("application/json") .body(policy) .post("/create") .then() .assertThat() .statusCode(200); }
3. 检查Policy类的JSON序列化
RestAssured需要把Policy对象序列化成JSON字符串才能发送请求,如果你的Policy类没有正确配置序列化(比如缺少Jackson/Gson的注解,或者没有无参构造函数),会导致请求体格式错误,Mock服务器可能直接断开连接:
- 给
Policy类添加必要的序列化配置,比如用Jackson的注解:import com.fasterxml.jackson.annotation.JsonProperty; public class Policy { @JsonProperty("name") private String name; // 必须要有无参构造函数,Jackson需要它来反序列化 public Policy() {} public Policy(String name) { this.name = name; } // getter和setter public String getName() { return name; } public void setName(String name) { this.name = name; } } - 或者手动把对象转成JSON字符串再传入body,避免自动序列化的问题:
import com.fasterxml.jackson.databind.ObjectMapper; @Test public final void testCreatePolicy() throws Exception { RestAssured.baseURI = "http://localhost"; RestAssured.port = 8080; Policy policy=new Policy(); policy.setName("policy123"); ObjectMapper mapper = new ObjectMapper(); String policyJson = mapper.writeValueAsString(policy); RestAssured.with() .contentType("application/json") .accept("application/json") .body(policyJson) .post("/create") .then() .assertThat() .statusCode(200); }
4. 简化Mock服务器的响应逻辑
你的PolicyResource方法里的响应代码可以简化,Response.ok()已经默认返回200状态码,重复设置status(200)虽然没问题,但可以改成更简洁的写法,确保响应能正确返回:
@POST @Path("/create") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response test(Policy messageBody) { System.out.println("policy: "+messageBody); // 简化响应逻辑 return Response.ok().build(); }
5. 排查端口占用问题
如果以上步骤都没问题,检查8080端口是否被其他程序占用,导致Mock服务器启动失败:
- Windows系统:打开命令提示符执行
netstat -ano | findstr :8080,查看PID对应的程序,结束占用端口的进程后重新启动测试。 - Linux/Mac系统:执行
lsof -i :8080查看占用端口的进程,用kill -9 <PID>结束进程。
附上你提供的原始代码和异常信息,方便对照:
测试类代码
public class PolicyResourceTest { private static MockRESTServer server; @BeforeClass public static void setUpBeforeClass() throws Exception { server = new MockRESTServer(8080, new PolicyResource()); server.start(); } @AfterClass public static void tearDownAfterClass() throws Exception { server.stop(); } @Test public final void testCreatePolicy() { Policy policy=new Policy(); policy.setName("policy123"); RestAssured.with() .contentType("application/json") .accept("application/json") .body(policy) .post("/create") .then() .assertThat() .statusCode(200); } }
资源类代码
@Path("/") public class PolicyResource { @POST @Path("/create") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response test( Policy messageBody) { System.out.println("policy: "+messageBody); return Response.ok().status(200).build(); } }
异常信息
org.apache.http.NoHttpResponseException: localhost:8080 failed to respond at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141) at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56) at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259) at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281) at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:257) at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:207) at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273) at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:684) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:486) at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) at org.apache.http.client.HttpClient$execute$0.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133) at io.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:2028) at io.restassured.internal.http.HTTPBuilder.post(HTTPBuilder.java:349) at io.restassured.internal.http.HTTPBuilder$post$2.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133) at io.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:1202) 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:498) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
内容的提问来源于stack exchange,提问作者Anju Singh
相关产品推荐
相关产品推荐

