2017-03-13 5 views
1

In einem Spring-Boot-Projekt möchte ich meine ErrorController mit Junit testen. Der Code ist wie das folgende Snippet.So testen Sie den allgemeinen Fehler ErrorController in Spring-Boot mit Junit

@RestController 
public class ApiErrorController implements ErrorController { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ApiErrorController.class); 

    @Value("${server.error.path}") 
    private String errorPath; 

    @Override 
    public String getErrorPath() { 
    return this.errorPath; 
    } 

    @RequestMapping("/error") 
    public ResponseEntity<ErrorResult> error(HttpServletRequest request, HttpServletResponse response) { 

    String requestURI = (String) request.getAttribute("javax.servlet.forward.request_uri"); 
    LOGGER.info("error handling start url = {}", requestURI); 

    String servletMessage = (String) request.getAttribute("javax.servlet.error.message"); 
    Integer servletStatus = (Integer) request.getAttribute("javax.servlet.error.status_code"); 

    String[] messages = new String[0]; 
    if (!StringUtils.isNullOrEmpty(servletMessage)) { 
     messages = new String[] { servletMessage }; 
    } 
    HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; 
    try { 
     if (servletStatus != null && servletStatus instanceof Integer) { 
     status = HttpStatus.valueOf(servletStatus); 
     } 
    } catch (Exception ex) { // test this exception 
     LOGGER.warn("http status not converted.{}", request.getAttribute("javax.servlet.error.status_code"), ex); 
    } 
    ErrorResult body = new ErrorResult(); 
    body.setMessages(messages); 
    ResponseEntity<ErrorResult> responseResult = new ResponseEntity<>(body, status); 
    return responseResult; 
    } 
} 

Wenn ein Unternehmen Ausnahme in meinem Controller-geschehen (zum Beispiel AbcController), dann geht das Programm in die ExceptionControllerAdvice Klasse. Wenn eine Ausnahme in ExceptionControllerAdvice aufgetreten ist, dann geht das Programm in die obige ApiErrorController-Klasse.

Kann mir jemand sagen, wie man den Fall, dass HttpStatus.valueOf(servletStatus) scheitern? Zusätzlich möchte ich request.getAttribute("javax.servlet.error.message") eine nicht leere Zeichenfolge zurückgeben. Wie erreiche ich, was ich testen möchte?

Übrigens, ich möchte nicht nur die Logik von error Methode testen. Ich möchte AbcController verwenden, die ich erwähnte, um den Test zu machen. Was ich will ist, wenn ein Fehler in AbcController auftritt, dann kann die error Methode in ApiErrorController erfolgreich damit umgehen.

APPEND: Zum Beispiel ExceptionControllerAdvice wird das Geschäft Ausnahme behandeln.

@ControllerAdvice(annotations = RestController.class) 
public class ExceptionControllerAdvice { 
    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionControllerAdvice.class); 

    @ExceptionHandler({ BusinessCloudException.class }) 
    public ResponseEntity<ErrorResult> handleBlCloudException(HttpServletRequest request, HttpServletResponse response, 
                  BlCloudException ex) { 

    HttpStatus status = ErrorUtils.toHttpStatus(ex.getType()); 
    ErrorResult body = new ErrorResult(); 
    body.setMessages(ex.getMessageArray()); 
    ResponseEntity<ErrorResult> responseResult = new ResponseEntity<>(body, status); 
    return responseResult; 
    } 
} 

Wenn es einen Fehler in der handleBlCloudException Methode passiert ist, dann geht das Programm in ApiErrorController diesen Fehler zu behandeln.

Wie erzeugt das Programm die spezifischen servletStatus und javax.servlet.error.message? Wie kann man das verspotten?

Antwort

0

Zunächst einmal ist in dieser Fehlermethode ziemlich viel los. Sie könnten einen Teil der Logik in eine spezielle Klasse/öffentliche Methode verschieben.

Abgesehen davon würde ich Mockito empfehlen.

Fist of all schaffen ein Verfahren der Httpstatus Retrieval zu kapseln:

HttpStatus getHttpStatusByServletStatus(Integer servletStatus){ 
    return HttpStatus.valueOf(servletStatus); 
} 

und Ihren Code ändern:

if (servletStatus != null && servletStatus instanceof Integer) { 
    status = getHttpStatusByServletStatus(servletStatus); 
    } 

Dann Klasse der Test:

öffentlichen ApiErrorControllerTest {

@Spy 
private ApiErrorController apiErrorController; 

@Mock 
HttpServletRequest requestMock; 
@Mock 
HttpServletResponse responseMock; 

@Befire 
public void init(){ 
    MockitoAnnotations.initMocks(this); 
} 

@Test 
public void test(){ 
    // Arrange 

    HttpStatus expectedStatus = // expected status 
    String expectedErrorMessage = // .. 

    doReturn(expectedStatus).when(apiErrorController) 
    .getHttpStatusByServletStatus(Mockito.anyString()); 

    when(requestMock.getAttribute("javax.servlet.error.message")) 
    .thenReturn(expectedErrorMessage); 

    // other setup.. 

    // Act 
    apiErrorController.error(requestMock, responseMock); 

    // Assertions 
} 
+0

T Danke. Aber ich möchte nicht nur die Logik der "Fehler" -Methode testen. Ich würde gerne 'AbcController' verwenden, den ich erwähnte, um den Test zu machen. Was ich will ist, wenn ein Fehler in'AbcController' auftritt, dann kann die 'error' Methode in' ApiErrorController' diese erfolgreich verarbeiten. – niaomingjian

+0

Sie möchten also grundsätzlich einen Integrationstest schreiben? –

+0

Ja, das kann man meinen. Vielleicht sieht es nach einem Integrationstest aus. – niaomingjian

Verwandte Themen