17
17
package org .springframework .boot .test .autoconfigure .web .servlet ;
18
18
19
19
import java .io .PrintStream ;
20
+ import java .io .PrintWriter ;
21
+ import java .io .StringWriter ;
22
+ import java .util .ArrayList ;
20
23
import java .util .Collection ;
24
+ import java .util .List ;
21
25
22
26
import javax .servlet .Filter ;
23
27
28
+ import org .apache .commons .logging .Log ;
29
+ import org .apache .commons .logging .LogFactory ;
30
+
31
+ import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
24
32
import org .springframework .boot .web .servlet .DelegatingFilterProxyRegistrationBean ;
25
33
import org .springframework .boot .web .servlet .FilterRegistrationBean ;
26
34
import org .springframework .boot .web .servlet .ServletContextInitializer ;
27
35
import org .springframework .boot .web .servlet .ServletContextInitializerBeans ;
36
+ import org .springframework .context .ApplicationContext ;
37
+ import org .springframework .context .ConfigurableApplicationContext ;
38
+ import org .springframework .test .web .servlet .MvcResult ;
28
39
import org .springframework .test .web .servlet .ResultHandler ;
29
- import org .springframework .test .web .servlet .result .MockMvcResultHandlers ;
30
40
import org .springframework .test .web .servlet .result .PrintingResultHandler ;
31
41
import org .springframework .test .web .servlet .setup .ConfigurableMockMvcBuilder ;
32
42
import org .springframework .util .Assert ;
@@ -50,6 +60,8 @@ public class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomi
50
60
51
61
private MockMvcPrint print = MockMvcPrint .DEFAULT ;
52
62
63
+ private boolean printOnlyOnFailure = true ;
64
+
53
65
/**
54
66
* Create a new {@link SpringBootMockMvcBuilderCustomizer} instance.
55
67
* @param context the source application context
@@ -71,13 +83,25 @@ public void customize(ConfigurableMockMvcBuilder<?> builder) {
71
83
}
72
84
73
85
private ResultHandler getPrintHandler () {
86
+ LinesWriter writer = getLinesWriter ();
87
+ if (writer == null ) {
88
+ return null ;
89
+ }
90
+ if (this .printOnlyOnFailure ) {
91
+ writer = new DeferredLinesWriter (this .context , writer );
92
+ }
93
+ return new LinesWritingResultHandler (writer );
94
+ }
95
+
96
+ private LinesWriter getLinesWriter () {
74
97
if (this .print == MockMvcPrint .NONE ) {
75
98
return null ;
76
99
}
77
100
if (this .print == MockMvcPrint .LOG_DEBUG ) {
78
- return MockMvcResultHandlers . log ();
101
+ return new LoggingLinesWriter ();
79
102
}
80
- return new SystemResultHandler (this .print );
103
+ return new SystemLinesWriter (this .print );
104
+
81
105
}
82
106
83
107
private void addFilters (ConfigurableMockMvcBuilder <?> builder ) {
@@ -129,47 +153,166 @@ public MockMvcPrint getPrint() {
129
153
return this .print ;
130
154
}
131
155
156
+ public void setPrintOnlyOnFailure (boolean printOnlyOnFailure ) {
157
+ this .printOnlyOnFailure = printOnlyOnFailure ;
158
+ }
159
+
160
+ public boolean isPrintOnlyOnFailure () {
161
+ return this .printOnlyOnFailure ;
162
+ }
163
+
132
164
/**
133
- * {@link PrintingResultHandler} to deal with {@code System.out} and
134
- * {@code System.err} printing. The actual {@link PrintStream} used to write the
135
- * response is obtained as late as possible in case an {@code OutputCaptureRule} is
136
- * being used.
165
+ * {@link ResultHandler} that prints {@link MvcResult} details to a given
166
+ * {@link LinesWriter}.
137
167
*/
138
- private static class SystemResultHandler extends PrintingResultHandler {
168
+ private static class LinesWritingResultHandler implements ResultHandler {
169
+
170
+ private final LinesWriter writer ;
139
171
140
- protected SystemResultHandler ( MockMvcPrint print ) {
141
- super ( new SystemResultValuePrinter ( print )) ;
172
+ LinesWritingResultHandler ( LinesWriter writer ) {
173
+ this . writer = writer ;
142
174
}
143
175
144
- private static class SystemResultValuePrinter implements ResultValuePrinter {
176
+ @ Override
177
+ public void handle (MvcResult result ) throws Exception {
178
+ LinesPrintingResultHandler delegate = new LinesPrintingResultHandler ();
179
+ delegate .handle (result );
180
+ delegate .write (this .writer );
181
+ }
145
182
146
- private final MockMvcPrint print ;
183
+ private static class LinesPrintingResultHandler extends PrintingResultHandler {
147
184
148
- SystemResultValuePrinter ( MockMvcPrint print ) {
149
- this . print = print ;
185
+ protected LinesPrintingResultHandler ( ) {
186
+ super ( new Printer ()) ;
150
187
}
151
188
152
- @ Override
153
- public void printHeading (String heading ) {
154
- getWriter ().println ();
155
- getWriter ().println (String .format ("%s:" , heading ));
189
+ public void write (LinesWriter writer ) {
190
+ writer .write (((Printer ) getPrinter ()).getLines ());
156
191
}
157
192
158
- @ Override
159
- public void printValue (String label , Object value ) {
160
- if (value != null && value .getClass ().isArray ()) {
161
- value = CollectionUtils .arrayToList (value );
193
+ private static class Printer implements ResultValuePrinter {
194
+
195
+ private final List <String > lines = new ArrayList <String >();
196
+
197
+ @ Override
198
+ public void printHeading (String heading ) {
199
+ this .lines .add ("" );
200
+ this .lines .add (String .format ("%s:" , heading ));
162
201
}
163
- getWriter ().println (String .format ("%17s = %s" , label , value ));
202
+
203
+ @ Override
204
+ public void printValue (String label , Object value ) {
205
+ if (value != null && value .getClass ().isArray ()) {
206
+ value = CollectionUtils .arrayToList (value );
207
+ }
208
+ this .lines .add (String .format ("%17s = %s" , label , value ));
209
+ }
210
+
211
+ public List <String > getLines () {
212
+ return this .lines ;
213
+ }
214
+
215
+ }
216
+
217
+ }
218
+
219
+ }
220
+
221
+ /**
222
+ * Strategy interface to write MVC result lines.
223
+ */
224
+ interface LinesWriter {
225
+
226
+ void write (List <String > lines );
227
+
228
+ }
229
+
230
+ /**
231
+ * {@link LinesWriter} used to defer writing until errors are detected.
232
+ * @see MockMvcPrintOnlyOnFailureTestExecutionListener
233
+ */
234
+ static class DeferredLinesWriter implements LinesWriter {
235
+
236
+ private static final String BEAN_NAME = DeferredLinesWriter .class .getName ();
237
+
238
+ private final LinesWriter delegate ;
239
+
240
+ private final List <String > lines = new ArrayList <String >();
241
+
242
+ DeferredLinesWriter (WebApplicationContext context , LinesWriter delegate ) {
243
+ Assert .state (context instanceof ConfigurableApplicationContext ,
244
+ "A ConfigurableApplicationContext is required for printOnlyOnFailure" );
245
+ ((ConfigurableApplicationContext ) context ).getBeanFactory ()
246
+ .registerSingleton (BEAN_NAME , this );
247
+ this .delegate = delegate ;
248
+ }
249
+
250
+ @ Override
251
+ public void write (List <String > lines ) {
252
+ this .lines .addAll (lines );
253
+ }
254
+
255
+ public void writeDeferredResult () {
256
+ this .delegate .write (this .lines );
257
+ }
258
+
259
+ public static DeferredLinesWriter get (ApplicationContext applicationContext ) {
260
+ try {
261
+ return applicationContext .getBean (BEAN_NAME , DeferredLinesWriter .class );
262
+ }
263
+ catch (NoSuchBeanDefinitionException ex ) {
264
+ return null ;
164
265
}
266
+ }
267
+
268
+ }
165
269
166
- private PrintStream getWriter () {
167
- if (this .print == MockMvcPrint .SYSTEM_ERR ) {
168
- return System .err ;
270
+ /**
271
+ * {@link LinesWriter} to output results to the log.
272
+ */
273
+ private static class LoggingLinesWriter implements LinesWriter {
274
+
275
+ private static final Log logger = LogFactory
276
+ .getLog ("org.springframework.test.web.servlet.result" );
277
+
278
+ @ Override
279
+ public void write (List <String > lines ) {
280
+ if (logger .isDebugEnabled ()) {
281
+ StringWriter stringWriter = new StringWriter ();
282
+ PrintWriter printWriter = new PrintWriter (stringWriter );
283
+ for (String line : lines ) {
284
+ printWriter .println (line );
169
285
}
170
- return System .out ;
286
+ logger .debug ("MvcResult details:\n " + stringWriter );
287
+ }
288
+ }
289
+
290
+ }
291
+
292
+ /**
293
+ * {@link LinesWriter} to output results to {@code System.out} or {@code System.err}.
294
+ */
295
+ private static class SystemLinesWriter implements LinesWriter {
296
+
297
+ private final MockMvcPrint print ;
298
+
299
+ SystemLinesWriter (MockMvcPrint print ) {
300
+ this .print = print ;
301
+ }
302
+
303
+ @ Override
304
+ public void write (List <String > lines ) {
305
+ PrintStream printStream = getPrintStream ();
306
+ for (String line : lines ) {
307
+ printStream .println (line );
171
308
}
309
+ }
172
310
311
+ private PrintStream getPrintStream () {
312
+ if (this .print == MockMvcPrint .SYSTEM_ERR ) {
313
+ return System .err ;
314
+ }
315
+ return System .out ;
173
316
}
174
317
175
318
}
0 commit comments