Spring 使用TestRestTemplate时出现异常

Spring 使用TestRestTemplate时出现异常,spring,rest,testing,spring-boot,Spring,Rest,Testing,Spring Boot,我有一个普通的SpringBoot应用程序,它带有自定义的身份验证过滤器,可以正常工作 但我在集成测试中使用TestRestTemplate时遇到了问题 我想在这里检查,如果有错误的信用用户不能登录。 但我没有得到401状态的响应,而是得到了一个例外: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: cannot retry due to server authent

我有一个普通的SpringBoot应用程序,它带有自定义的身份验证过滤器,可以正常工作

但我在集成测试中使用TestRestTemplate时遇到了问题

我想在这里检查,如果有错误的信用用户不能登录。 但我没有得到401状态的响应,而是得到了一个例外:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: cannot retry due to server authentication, in streaming mode; nested exception is java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:228)
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.read(MappingJackson2HttpMessageConverter.java:220)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:95)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:795)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:779)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:559)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:512)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:454)
    at cz.angular.security.basic.rest.AuthorizeControllerTest.userWithWrongCreditials(AuthorizeControllerTest.java:64)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1280)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
    at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
    at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
    at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
    at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:552)
    ... 42 more
内部弹簧投掷 org.springframework.security.authentication.BadCredentialsException,但在实际应用程序使用中,它会转换为json响应

curl -H "Content-Type: application/json" -d '{"name":"user","password":"password-wrong"}' http://localhost:8080/login
{"timestamp":"2014-12-07T10:07:27.166+0000","status":401,"error":"Unauthorized","exception":"org.springframework.security.authentication.BadCredentialsException","message":"Bad credentials","path":"/login"}
使用curl时,我得到了正常的反应

curl -H "Content-Type: application/json" -d '{"name":"user","password":"password-wrong"}' http://localhost:8080/login
{"timestamp":"2014-12-07T10:07:27.166+0000","status":401,"error":"Unauthorized","exception":"org.springframework.security.authentication.BadCredentialsException","message":"Bad credentials","path":"/login"}
测试代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest("server.port:9999")
public class AuthorizeControllerTest {

  public static final String LOCALHOST = "http://localhost:9999";

...

  @Test
  public void userWithWrongCreditials() throws Exception {
    RestTemplate rest = new TestRestTemplate();

    Credentials credentials = new Credentials();
    credentials.setName("user");
    credentials.setPassword("password-wrong");

    ResponseEntity<Map> response =
      rest.exchange(
        LOCALHOST + "/login",
        HttpMethod.POST,
        new HttpEntity<Credentials>(credentials),
        Map.class);

    assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
  }
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(类=Application.class)
@WebAppConfiguration
@IntegrationTest(“服务器端口:9999”)
公共类授权控制器测试{
公共静态最终字符串LOCALHOST=”http://localhost:9999";
...
@试验
public void userWithErrorCreditials()引发异常{
RestTemplate rest=新TestRestTemplate();
凭据=新凭据();
credentials.setName(“用户”);
凭证。设置密码(“密码错误”);
反应性反应=
休息室(
LOCALHOST+“/login”,
HttpMethod.POST,
新的HttpEntity(凭证),
地图(类别),;
assertEquals(HttpStatus.UNAUTHORIZED,response.getStatusCode());
}
}
整个项目可以在存储库中看到

在AuthorizeControllerTest中,您可以看到通过测试和失败测试

我尝试过很多事情,比如设置内容类型等等,但是运气不好。
如果有任何想法,我将不胜感激。

我认为Jackson不会知道如何将JSON转换为
对象。尝试
Map
或其他方法?

您需要Apache HTTP客户端能够使用
TestRestTemplate
自己处理错误。你的项目对我很有用

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <scope>test</scope>
    </dependency>

org.apache.httpcomponents
httpclient
测试

(我还删除了重复的junit、mockito和spring测试依赖项。)

在成功登录测试中,我使用UserInfo对象,这当然有效。在错误的登录测试中,我也尝试了Map/LinkedHashMap/String,Object是我最后一次尝试,但结果总是一样的。也许你应该更新问题,使其更接近于可能有效的内容(即使用
Map
作为响应类型)?对我有效。您确定这是来自Spring Boot的
TestRestTemplate
吗?是的,它是来自Spring Boot的TestRestTemplate。我会尽快提供完整的代码,也许在过滤器实现中有一些问题,但我很好奇为什么应用程序能按预期工作(当给出错误的密码时返回401)@DaveSyer我已经编辑了问题并添加了完整代码的存储库。在AuthorizeControllerTest中,您可以看到通过测试和失败测试。是的,它可以工作。非常感谢,你帮了我很多。所以,如果我正确地得到它,httpclient将取代TestRestTemplate中的默认httpclient?好的,您节省了我的时间。谢谢。但是,为什么这个鬼把戏能解决问题@戴夫:在春天5号,这仍然是真的吗?在RestTemplate中:741
ResourceAccessException
似乎总是在出现
IOException
时抛出,我认为没有任何根本性的改变。注意:这个问题是关于
TestRestTemplate
。我所要做的就是删除这个依赖项,突然这个异常消失了。