diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java index 2fecdadb1f4..693a5431d03 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/servlet/SpringBootMockMvcBuilderCustomizer.java @@ -52,6 +52,7 @@ import org.springframework.web.context.WebApplicationContext; * * @author Phillip Webb * @author Andy Wilkinson + * @author Moritz Halbritter * @since 1.4.0 */ public class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer { @@ -100,7 +101,7 @@ public class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomi return null; } if (this.print == MockMvcPrint.LOG_DEBUG) { - return new LoggingLinesWriter(); + return (LoggingLinesWriter.isDebugEnabled()) ? new LoggingLinesWriter() : null; } return new SystemLinesWriter(this.print); } @@ -188,7 +189,12 @@ public class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomi if (value != null && value.getClass().isArray()) { value = CollectionUtils.arrayToList(value); } - this.lines.add(String.format("%17s = %s", label, value)); + try { + this.lines.add("%17s = %s".formatted(label, value)); + } + catch (RuntimeException ex) { + this.lines.add("%17s = << Exception '%s' occurred while formatting >>".formatted(label, ex)); + } } List getLines() { @@ -273,6 +279,10 @@ public class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomi } } + static boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + } /** diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController1.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController1.java index 3e8aabfb424..3fbd7e093e3 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController1.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/ExampleController1.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,14 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.WebRequest; /** * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests. * * @author Phillip Webb + * @author Moritz Halbritter */ @RestController public class ExampleController1 { @@ -44,4 +47,16 @@ public class ExampleController1 { return "Hello"; } + @GetMapping("/formatting") + public String formatting(WebRequest request) { + Object formattingFails = new Object() { + @Override + public String toString() { + throw new IllegalStateException("Formatting failed"); + } + }; + request.setAttribute("attribute-1", formattingFails, RequestAttributes.SCOPE_SESSION); + return "formatting"; + } + } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/MockMvcSpringBootTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/MockMvcSpringBootTestIntegrationTests.java index 1ac7af71400..b267b7391af 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/MockMvcSpringBootTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/MockMvcSpringBootTestIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} (i.e. full integration test). * * @author Phillip Webb + * @author Moritz Halbritter */ @SpringBootTest @AutoConfigureMockMvc(print = MockMvcPrint.SYSTEM_ERR, printOnlyOnFailure = false) @@ -83,4 +84,11 @@ class MockMvcSpringBootTestIntegrationTests { webTestClient.get().uri("/one").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("one"); } + @Test + void shouldNotFailIfFormattingValueThrowsException(CapturedOutput output) throws Exception { + this.mvc.perform(get("/formatting")).andExpect(content().string("formatting")).andExpect(status().isOk()); + assertThat(output).contains( + "Session Attrs = << Exception 'java.lang.IllegalStateException: Formatting failed' occurred while formatting >>"); + } + }