测试@NotNull时集成测试失败

ers*_*lan 5 java integration-testing spring-data-jpa spring-boot

我克隆了这个项目并将Hotel.java更改为:

@Entity
public class Hotel implements Serializable {
  .
  .
  @javax.validation.constraints.NotNull
//@Column(nullable = false)
  private String address;
  .
  .
}
Run Code Online (Sandbox Code Playgroud)

在发布帖子请求时:

curl -H "Content-Type: application/json" -X POST -d '{}' http://localhost:8080/api/hotels
Run Code Online (Sandbox Code Playgroud)

回应是:

{
  "timestamp": 1479213670718,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "javax.validation.ConstraintViolationException",
  "message": "org.springframework.web.util.NestedServletException:   Request processing failed; nested exception is javax.validation.ConstraintViolationException: Validation failed for classes [sample.data.rest.domain.Hotel] during persist time for groups [javax.validation.groups.Default, ]\nList of constraint violations:[\n\tConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=address, rootBeanClass=class sample.data.rest.domain.Hotel, messageTemplate='{javax.validation.constraints.NotNull.message}'}\n]",
  "path": "/api/hotels"
}
Run Code Online (Sandbox Code Playgroud)

然后我写了这个案例的测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("scratch")
public class SampleDataRestApplicationTests {
  .
  .

  @Test
  public void createHotel_andExpectServerError() throws Exception {
    this.mvc.perform(post("/api/hotels").content("{}"))
            .andExpect(status().is5xxServerError());
  }

}
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,它会抛出此错误:

org.springframework.web.util.NestedServletException: 
Request processing failed; nested exception is javax.validation.ConstraintViolationException: 
Validation failed for classes [sample.data.rest.domain.Hotel] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
  ConstraintViolationImpl{
    interpolatedMessage='may not be null', 
    propertyPath=address, rootBeanClass=class sample.data.rest.domain.Hotel, 
    messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
Run Code Online (Sandbox Code Playgroud)

所以它失败了,但我希望它能通过.

看起来像处理ConstraintViolationException的默认exceptionHandler通常在测试中不可用.

谢谢.

Kev*_*ers 0

我无法重现您的结果,但也许可以通过澄清一些事情来更接近您的问题。

如果我在我的机器上执行你的curl命令(带有附加的-v标志来获取标头),确切地说,我会收到客户端错误409 Conflict

curl -v -H "Content-Type: application/json" -X POST -d '{}' http://localhost:8080/api/hotels
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /api/hotels HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 2
> 
* upload completely sent off: 2 out of 2 bytes
< HTTP/1.1 409 Conflict
< Date: Sun, 22 Jan 2017 12:29:45 GMT
< Content-Type: application/hal+json;charset=UTF-8
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
{"cause":{"cause":{"cause":null,"message":"NULL not allowed for column \"ADDRESS\"; SQL statement:\ninsert into hotel (id, address, city_id, name, zip) values (null, ?, ?, ?, ?) [23502-193]"},"message":"could not execute statement"},"message":"could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"}
Run Code Online (Sandbox Code Playgroud)

在我的 IDE (STS) 中执行测试时也会发生同样的情况:

java.lang.AssertionError: Range for response status value 409 expected:<SERVER_ERROR> but was:<CLIENT_ERROR>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
    at org.springframework.test.web.servlet.result.StatusResultMatchers$7.match(StatusResultMatchers.java:132)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
    ...
Run Code Online (Sandbox Code Playgroud)

因此,首先测试和正在运行的应用程序之间没有区别,DataIntegrityViolationException / ConstraintViolationException 在这两种情况下都映射到 409。

如果这是正确的则是另一个问题,但也许发送错误/无效的数据实际上是客户端错误。

如果你仍然想改变这一点,你必须添加你自己的 ExceptionHandler 也许以这样的方式:

import org.hibernate.exception.ConstraintViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@RestControllerAdvice
public class ConstraintViolationExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler({ ConstraintViolationException.class })
    public ResponseEntity<Object> handleConstraintViolationException(Exception ex, WebRequest request) {
        return handleExceptionInternal(ex, "I think it's the servers fault!", new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
    }

}
Run Code Online (Sandbox Code Playgroud)

也许这可以解决您的问题。给你一个提示。或者还有其他问题我没有得到解答?