Skip to content

Commit 3e58ca9

Browse files
authored
Merge pull request #488 from priyacshah/early_exit_junit_xml_feature
Fix for junit failure FIX #487
2 parents c8d0860 + becca9c commit 3e58ca9

File tree

7 files changed

+116
-19
lines changed

7 files changed

+116
-19
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ README.rst
4242

4343
# IDE configuration
4444
.idea/
45+
.venv/
46+
.vscode/

radish/extensions/junit_xml_writer.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,31 +113,34 @@ def generate_junit_xml(self, features, marker):
113113
if scenario.state is Step.State.FAILED:
114114
testsuite_states["failures"] += 1
115115

116+
if feature.starttime and feature.endtime:
117+
feature_duration = feature.duration.total_seconds()
118+
else:
119+
feature_duration = 0
116120
testsuite_element = etree.Element(
117121
"testsuite",
118122
name=feature.sentence,
119123
failures=str(testsuite_states["failures"]),
120124
errors=str(testsuite_states["errors"]),
121125
skipped=str(testsuite_states["skipped"]),
122126
tests=str(testsuite_states["tests"]),
123-
time="%.3f" % feature.duration.total_seconds(),
127+
time=f"{feature_duration:.3f}",
124128
)
125129

126130
for scenario in (s for s in feature.all_scenarios if not isinstance(s, (ScenarioOutline, ScenarioLoop))):
127131
if not scenario.has_to_run(world.config.scenarios):
128132
continue
129133

130-
if scenario.state not in [
131-
Step.State.UNTESTED,
132-
Step.State.PENDING,
133-
Step.State.SKIPPED,
134-
]:
135-
testcase_element = etree.Element(
136-
"testcase",
137-
classname=feature.sentence,
138-
name=scenario.sentence,
139-
time="%.3f" % scenario.duration.total_seconds(),
140-
)
134+
if scenario.starttime and scenario.endtime:
135+
testcase_duration = scenario.duration.total_seconds()
136+
else:
137+
testcase_duration = 0
138+
testcase_element = etree.Element(
139+
"testcase",
140+
classname=feature.sentence,
141+
name=scenario.sentence,
142+
time=f"{testcase_duration:.3f}",
143+
)
141144

142145
if world.config.junit_relaxed:
143146
properties_element = etree.Element("properties")
@@ -179,10 +182,5 @@ def generate_junit_xml(self, features, marker):
179182

180183
testsuites_element.append(testsuite_element)
181184

182-
content = etree.tostring(
183-
testsuites_element,
184-
pretty_print=True,
185-
xml_declaration=True,
186-
encoding="utf-8",
187-
)
185+
content = etree.tostring(testsuites_element, pretty_print=True, xml_declaration=True, encoding="utf-8")
188186
self._write_xml_to_disk(content)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Feature: Test summing numbers
2+
In order to test the basic
3+
features of radish I test
4+
to sum numbers.
5+
6+
Scenario: Sum two numbers
7+
Given I have the number 5
8+
And I have the number 3
9+
When I sum them
10+
Then I expect the result to be 8
11+
12+
Scenario: Sum three numbers
13+
Given I have the number 5
14+
And I have the number 3
15+
And I have the number 2
16+
When I sum them
17+
Then I expect the result to be 10
18+
Then I crash
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Feature: Test summing numbers
2+
In order to test the basic
3+
features of radish I test
4+
to sum numbers.
5+
6+
Scenario: Sum two numbers
7+
Given I have the number 5
8+
And I have the number 3
9+
When I sum them
10+
Then I expect the result to be 8
11+
12+
Scenario: Sum three numbers
13+
Given I have the number 5
14+
And I have the number 3
15+
And I have the number 2
16+
When I sum them
17+
Then I expect the result to be 10
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import sys
2+
3+
from radish import then, when
4+
from radish.stepregistry import step
5+
6+
7+
@step("I have the number {number:g}")
8+
def have_number(step, number):
9+
step.context.numbers.append(int(number))
10+
11+
12+
@when("I sum them")
13+
def sum_numbers(step):
14+
step.context.result = sum(step.context.numbers)
15+
16+
17+
@then("I expect the result to be {result:g}")
18+
def expect_result(step, result):
19+
assert step.context.result == result
20+
21+
22+
@then("I crash")
23+
def crash(step):
24+
sys.exit(1)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from radish import before
2+
3+
4+
@before.each_scenario
5+
def init_numbers(scenario):
6+
scenario.context.numbers = []

tests/unit/extensions/test_junit_xml_writer.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Copyright: MIT, Timo Furrer <[email protected]>
88
"""
99

10+
import re
1011
from datetime import datetime, timezone
1112

1213
import pytest
@@ -16,6 +17,7 @@
1617
from radish.feature import Feature
1718
from radish.model import Tag
1819
from radish.scenario import Scenario
20+
from radish.stepmodel import Step
1921
from radish.terrain import world
2022

2123

@@ -27,7 +29,7 @@ def test_empty_feature_list():
2729
writer.generate_junit_xml(no_features, "marker-is-ignored")
2830

2931

30-
def test_singel_feature_list(mocker):
32+
def test_single_feature_list(mocker):
3133
stub = mocker.patch("radish.extensions.junit_xml_writer.JUnitXMLWriter._write_xml_to_disk")
3234

3335
first_feature = Feature(1, "Feature", "I am a feature", "foo.feature", 1, tags=None)
@@ -108,3 +110,33 @@ def test_relaxed_mode_adding_tags_to_junit(mocker):
108110

109111
assert "author" in str(stub.call_args[0])
110112
assert "batman" in str(stub.call_args[0])
113+
114+
115+
def test_early_exit_feature_list(mocker):
116+
stub = mocker.patch("radish.extensions.junit_xml_writer.JUnitXMLWriter._write_xml_to_disk")
117+
118+
first_feature = Feature(1, "Feature", "I am a feature", "foo.feature", 1, tags=None)
119+
first_feature.starttime = datetime.now(timezone.utc)
120+
first_feature.endtime = datetime.now(timezone.utc)
121+
second_feature = Feature(2, "Feature", "Did not run", "foo.feature", 1, tags=None)
122+
scenario = Scenario(
123+
1, "Scenario", "Did not run", "foo.feature", 1, parent=None, tags=None, preconditions=None, background=None
124+
)
125+
scenario.steps = [Step(1, "Foo", "foo.feature", 2, None, False)]
126+
second_feature.scenarios = [scenario]
127+
assert second_feature.state not in [Step.State.PASSED, Step.State.FAILED]
128+
129+
features = [first_feature, second_feature]
130+
131+
writer = JUnitXMLWriter()
132+
writer.generate_junit_xml(features, "marker-is-ignored")
133+
134+
result = str(stub.call_args[0])
135+
feature_regex = re.compile(r"<testsuite[^>]*name=\"([^\"]+)\"([^>]*)>")
136+
matches = feature_regex.findall(result)
137+
assert len(matches) == 2
138+
f1_match = next(m for m in matches if m[0] == "I am a feature")
139+
f2_match = next(m for m in matches if m[0] == "Did not run")
140+
assert 'tests="0"' in f1_match[1] # f1 contains no scenarios
141+
assert 'skipped="1"' in f2_match[1] # f2 contains one untested scenario (it was skipped)
142+
assert "<skipped" in result # there is a skipped testcase element

0 commit comments

Comments
 (0)