Skip to content

Commit 37d9bcb

Browse files
committed
Fix issues in the JUnitFormatter
Change the JUnitFormatter to handle failures in the before and after hooks properly. Also change the JUnitFormatter to handle both all-steps-first execution and one-step-at-the-time execution.
1 parent ebfb7aa commit 37d9bcb

File tree

1 file changed

+76
-38
lines changed

1 file changed

+76
-38
lines changed

core/src/main/java/cucumber/runtime/formatter/JUnitFormatter.java

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ public void feature(Feature feature) {
6363

6464
@Override
6565
public void background(Background background) {
66-
testCase = new TestCase();
67-
root = testCase.createElement(doc);
66+
if (!isCurrentTestCaseCreatedNameless()) {
67+
testCase = new TestCase();
68+
root = testCase.createElement(doc);
69+
}
6870
}
6971

7072
@Override
7173
public void scenario(Scenario scenario) {
72-
if (testCase != null && testCase.scenario == null) {
74+
if (isCurrentTestCaseCreatedNameless()) {
7375
testCase.scenario = scenario;
7476
} else {
7577
testCase = new TestCase(scenario);
@@ -81,6 +83,10 @@ public void scenario(Scenario scenario) {
8183
increaseAttributeValue(rootElement, "tests");
8284
}
8385

86+
private boolean isCurrentTestCaseCreatedNameless() {
87+
return testCase != null && testCase.scenario == null;
88+
}
89+
8490
@Override
8591
public void step(Step step) {
8692
if (testCase != null) testCase.steps.add(step);
@@ -111,6 +117,10 @@ public void result(Result result) {
111117

112118
@Override
113119
public void before(Match match, Result result) {
120+
if (!isCurrentTestCaseCreatedNameless()) {
121+
testCase = new TestCase();
122+
root = testCase.createElement(doc);
123+
}
114124
handleHook(result);
115125
}
116126

@@ -120,10 +130,8 @@ public void after(Match match, Result result) {
120130
}
121131

122132
private void handleHook(Result result) {
123-
if (result.getStatus().equals(Result.FAILED)) {
124-
testCase.results.add(result);
125-
}
126-
133+
testCase.hookResults.add(result);
134+
testCase.updateElement(doc, root);
127135
}
128136

129137
private void increaseAttributeValue(Element element, String attribute) {
@@ -136,6 +144,7 @@ private void increaseAttributeValue(Element element, String attribute) {
136144

137145
@Override
138146
public void scenarioOutline(ScenarioOutline scenarioOutline) {
147+
testCase = null;
139148
}
140149

141150
@Override
@@ -196,6 +205,7 @@ private TestCase() {
196205
static boolean treatSkippedAsFailure = false;
197206
final List<Step> steps = new ArrayList<Step>();
198207
final List<Result> results = new ArrayList<Result>();
208+
final List<Result> hookResults = new ArrayList<Result>();
199209

200210
private Element createElement(Document doc) {
201211
return doc.createElement("testcase");
@@ -207,51 +217,31 @@ private void writeElement(Document doc, Element tc) {
207217
}
208218

209219
public void updateElement(Document doc, Element tc) {
210-
long totalDurationNanos = 0;
211-
for (Result r : results) {
212-
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
213-
}
214-
215-
double totalDurationSeconds = ((double) totalDurationNanos) / 1000000000;
216-
String time = NUMBER_FORMAT.format(totalDurationSeconds);
217-
tc.setAttribute("time", time);
220+
tc.setAttribute("time", calculateTotalDurationString());
218221

219222
StringBuilder sb = new StringBuilder();
223+
addStepAndResultListing(sb);
220224
Result skipped = null, failed = null;
221-
for (int i = 0; i < steps.size(); i++) {
222-
int length = sb.length();
223-
Result result = results.get(i);
225+
for (Result result : results) {
224226
if ("failed".equals(result.getStatus())) failed = result;
225227
if ("undefined".equals(result.getStatus()) || "pending".equals(result.getStatus())) skipped = result;
226-
sb.append(steps.get(i).getKeyword());
227-
sb.append(steps.get(i).getName());
228-
do {
229-
sb.append(".");
230-
} while (sb.length() - length < 76);
231-
sb.append(result.getStatus());
232-
sb.append("\n");
228+
}
229+
for (Result result : hookResults) {
230+
if (failed == null && "failed".equals(result.getStatus())) failed = result;
233231
}
234232
Element child;
235233
if (failed != null) {
236-
sb.append("\nStackTrace:\n");
237-
StringWriter sw = new StringWriter();
238-
failed.getError().printStackTrace(new PrintWriter(sw));
239-
sb.append(sw.toString());
240-
child = doc.createElement("failure");
241-
child.setAttribute("message", failed.getErrorMessage());
242-
child.appendChild(doc.createCDATASection(sb.toString()));
234+
addStackTrace(sb, failed);
235+
child = createElementWithMessage(doc, sb, "failure", failed.getErrorMessage());
243236
} else if (skipped != null) {
244237
if (treatSkippedAsFailure) {
245-
child = doc.createElement("failure");
246-
child.setAttribute("message", "The scenario has pending or undefined step(s)");
238+
child = createElementWithMessage(doc, sb, "failure", "The scenario has pending or undefined step(s)");
247239
}
248240
else {
249-
child = doc.createElement("skipped");
241+
child = createElement(doc, sb, "skipped");
250242
}
251-
child.appendChild(doc.createCDATASection(sb.toString()));
252243
} else {
253-
child = doc.createElement("system-out");
254-
child.appendChild(doc.createCDATASection(sb.toString()));
244+
child = createElement(doc, sb, "system-out");
255245
}
256246

257247
Node existingChild = tc.getFirstChild();
@@ -262,6 +252,54 @@ public void updateElement(Document doc, Element tc) {
262252
}
263253
}
264254

255+
private String calculateTotalDurationString() {
256+
long totalDurationNanos = 0;
257+
for (Result r : results) {
258+
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
259+
}
260+
for (Result r : hookResults) {
261+
totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration();
262+
}
263+
double totalDurationSeconds = ((double) totalDurationNanos) / 1000000000;
264+
return NUMBER_FORMAT.format(totalDurationSeconds);
265+
}
266+
267+
private void addStepAndResultListing(StringBuilder sb) {
268+
for (int i = 0; i < steps.size(); i++) {
269+
int length = sb.length();
270+
String resultStatus = "not executed";
271+
if (i < results.size()) {
272+
resultStatus = results.get(i).getStatus();
273+
}
274+
sb.append(steps.get(i).getKeyword());
275+
sb.append(steps.get(i).getName());
276+
do {
277+
sb.append(".");
278+
} while (sb.length() - length < 76);
279+
sb.append(resultStatus);
280+
sb.append("\n");
281+
}
282+
}
283+
284+
private void addStackTrace(StringBuilder sb, Result failed) {
285+
sb.append("\nStackTrace:\n");
286+
StringWriter sw = new StringWriter();
287+
failed.getError().printStackTrace(new PrintWriter(sw));
288+
sb.append(sw.toString());
289+
}
290+
291+
private Element createElementWithMessage(Document doc, StringBuilder sb, String elementType, String message) {
292+
Element child = createElement(doc, sb, elementType);
293+
child.setAttribute("message", message);
294+
return child;
295+
}
296+
297+
private Element createElement(Document doc, StringBuilder sb, String elementType) {
298+
Element child = doc.createElement(elementType);
299+
child.appendChild(doc.createCDATASection(sb.toString()));
300+
return child;
301+
}
302+
265303
}
266304

267305
}

0 commit comments

Comments
 (0)