Skip to content

Commit 8a07e4c

Browse files
committed
junit formatter implementation, adapt pretty formatter
closes #14 background was not printed with outline scenarios in feature
1 parent b192f0b commit 8a07e4c

File tree

7 files changed

+208
-269
lines changed

7 files changed

+208
-269
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses)
22

3-
Copyright (c) 2015, DataDog.lt team
3+
Copyright (c) 2015-2016, DataDog.lt team
44
All rights reserved.
55

66
Redistribution and use in source and binary forms, with or without

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ See implementation examples:
144144

145145
### Changes
146146

147+
**2016-03-04**
148+
- added **junit** compatible output formatter, which prints **xml**
149+
results to **os.Stdout**
150+
- fixed #14 which skipped printing background steps when there was
151+
scenario outline in feature.
152+
147153
**2015-07-03**
148154
- changed **godog.Suite** from interface to struct. Context registration should be updated accordingly. The reason
149155
for change: since it exports the same methods and there is no need to mock a function in tests, there is no

fmt_junit.go

Lines changed: 109 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -3,205 +3,183 @@ package godog
33
import (
44
"encoding/xml"
55
"fmt"
6+
"io"
67
"os"
78
"time"
89

910
"gopkg.in/cucumber/gherkin-go.v3"
1011
)
1112

1213
func init() {
13-
Format("junit", "Prints out in junit compatible xml format", &junitFormatter{
14-
suites: make([]*junitTestSuites, 0),
14+
Format("junit", "Prints junit compatible xml to stdout", &junitFormatter{
15+
suite: &junitPackageSuite{
16+
Name: "main", // @TODO: it should extract package name
17+
TestSuites: make([]*junitTestSuite, 0),
18+
},
19+
started: time.Now(),
1520
})
1621
}
1722

1823
type junitFormatter struct {
19-
suites []*junitTestSuites
24+
suite *junitPackageSuite
25+
26+
// timing
27+
started time.Time
28+
caseStarted time.Time
29+
featStarted time.Time
30+
31+
outline *gherkin.ScenarioOutline
32+
outlineExample int
2033
}
2134

2235
func (j *junitFormatter) Feature(feature *gherkin.Feature, path string) {
23-
testSuites := &junitTestSuites{
24-
Name: feature.Name,
25-
TestSuites: make([]*junitTestSuite, 0),
36+
testSuite := &junitTestSuite{
37+
TestCases: make([]*TestCase, 0),
38+
Name: feature.Name,
2639
}
2740

28-
j.suites = append(j.suites, testSuites)
41+
if len(j.suite.TestSuites) > 0 {
42+
j.current().Time = time.Since(j.featStarted).String()
43+
}
44+
j.featStarted = time.Now()
45+
j.suite.TestSuites = append(j.suite.TestSuites, testSuite)
2946
}
3047

3148
func (j *junitFormatter) Node(node interface{}) {
32-
testSuite := &junitTestSuite{
33-
TestCases: make([]*TestCase, 0),
34-
Timestamp: time.Now(),
35-
}
49+
suite := j.current()
50+
tcase := &TestCase{}
3651

3752
switch t := node.(type) {
3853
case *gherkin.ScenarioOutline:
39-
testSuite.Name = t.Name
54+
j.outline = t
55+
return
4056
case *gherkin.Scenario:
41-
testSuite.Name = t.Name
42-
case *gherkin.Background:
43-
testSuite.Name = "Background"
57+
tcase.Name = t.Name
58+
suite.Tests++
59+
j.suite.Tests++
60+
case *gherkin.Examples:
61+
j.outlineExample = 0
62+
return
63+
case *gherkin.TableRow:
64+
j.outlineExample++
65+
tcase.Name = fmt.Sprintf("%s #%d", j.outline.Name, j.outlineExample)
66+
suite.Tests++
67+
j.suite.Tests++
68+
default:
69+
return
4470
}
45-
46-
currentSuites := j.currentSuites()
47-
currentSuites.TestSuites = append(currentSuites.TestSuites, testSuite)
71+
if len(suite.TestCases) > 0 {
72+
suite.current().Time = time.Since(j.caseStarted).String()
73+
}
74+
j.caseStarted = time.Now()
75+
suite.TestCases = append(suite.TestCases, tcase)
4876
}
4977

5078
func (j *junitFormatter) Failed(step *gherkin.Step, match *StepDef, err error) {
51-
testCase := &TestCase{
52-
Name: step.Text,
79+
suite := j.current()
80+
suite.Failures++
81+
j.suite.Failures++
82+
83+
tcase := suite.current()
84+
tcase.Status = "failed"
85+
tcase.Failure = &junitFailure{
86+
Message: fmt.Sprintf("%s %s: %s", step.Type, step.Text, err.Error()),
5387
}
54-
55-
testCase.Failure = &junitFailure{
56-
Contents: err.Error(),
57-
}
58-
59-
currentSuites := j.currentSuites()
60-
currentSuites.Failures++
61-
currentSuite := currentSuites.currentSuite()
62-
currentSuite.Failures++
63-
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
6488
}
6589

6690
func (j *junitFormatter) Passed(step *gherkin.Step, match *StepDef) {
67-
testCase := &TestCase{
68-
Name: step.Text,
69-
}
91+
suite := j.current()
7092

71-
currentSuites := j.currentSuites()
72-
currentSuites.Tests++
73-
currentSuite := currentSuites.currentSuite()
74-
currentSuite.Tests++
75-
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
93+
tcase := suite.current()
94+
tcase.Status = "passed"
7695
}
7796

7897
func (j *junitFormatter) Skipped(step *gherkin.Step) {
79-
testCase := &TestCase{
80-
Name: step.Text,
81-
}
82-
83-
currentSuites := j.currentSuites()
84-
currentSuite := currentSuites.currentSuite()
85-
currentSuite.Skipped++
86-
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
8798
}
8899

89100
func (j *junitFormatter) Undefined(step *gherkin.Step) {
90-
testCase := &TestCase{
91-
Name: step.Text,
92-
}
93-
94-
currentSuites := j.currentSuites()
95-
currentSuites.Disabled++
96-
currentSuite := currentSuites.currentSuite()
97-
currentSuite.Disabled++
98-
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
101+
suite := j.current()
102+
suite.Errors++
103+
j.suite.Errors++
104+
105+
tcase := suite.current()
106+
tcase.Status = "undefined"
107+
tcase.Error = append(tcase.Error, &junitError{
108+
Type: "undefined",
109+
Message: fmt.Sprintf("%s %s", step.Type, step.Text),
110+
})
99111
}
100112

101113
func (j *junitFormatter) Pending(step *gherkin.Step, match *StepDef) {
102-
testCase := &TestCase{
103-
Name: step.Text,
104-
}
105-
106-
testCase.Skipped = &junitSkipped{
107-
Contents: step.Text,
108-
}
109-
110-
currentSuites := j.currentSuites()
111-
currentSuite := currentSuites.currentSuite()
112-
currentSuite.Skipped++
113-
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
114+
suite := j.current()
115+
suite.Errors++
116+
j.suite.Errors++
117+
118+
tcase := suite.current()
119+
tcase.Status = "pending"
120+
tcase.Error = append(tcase.Error, &junitError{
121+
Type: "pending",
122+
Message: fmt.Sprintf("%s %s: TODO: write pending definition", step.Type, step.Text),
123+
})
114124
}
115125

116126
func (j *junitFormatter) Summary() {
127+
j.suite.Time = time.Since(j.started).String()
128+
io.WriteString(os.Stdout, xml.Header)
129+
117130
enc := xml.NewEncoder(os.Stdout)
118-
enc.Indent(" ", " ")
119-
if err := enc.Encode(j.suites); err != nil {
120-
fmt.Printf("error: %v\n", err)
131+
enc.Indent("", s(2))
132+
if err := enc.Encode(j.suite); err != nil {
133+
fmt.Println("failed to write junit xml:", err)
121134
}
122135
}
123136

124137
type junitFailure struct {
125-
Message string `xml:"message,attr"`
126-
Type string `xml:"type,attr"`
127-
Contents string `xml:",chardata"`
138+
Message string `xml:"message,attr"`
139+
Type string `xml:"type,attr,omitempty"`
128140
}
129141

130142
type junitError struct {
131-
Message string `xml:"message,attr"`
132-
Type string `xml:"type,attr"`
133-
Contents string `xml:",chardata"`
134-
}
135-
136-
type junitProperty struct {
137-
Name string `xml:"name,attr"`
138-
Value string `xml:"value,attr"`
139-
}
140-
141-
type junitSkipped struct {
142-
Contents string `xml:",chardata"`
143-
}
144-
145-
type SystemErr struct {
146-
Contents string `xml:",chardata"`
147-
}
148-
149-
type SystemOut struct {
150-
Contents string `xml:",chardata"`
143+
XMLName xml.Name `xml:"error,omitempty"`
144+
Message string `xml:"message,attr"`
145+
Type string `xml:"type,attr"`
151146
}
152147

153148
type TestCase struct {
154-
XMLName xml.Name `xml:"testcase"`
155-
Name string `xml:"name,attr"`
156-
Classname string `xml:"classname,attr"`
157-
Assertions string `xml:"assertions,attr"`
158-
Status string `xml:"status,attr"`
159-
Time string `xml:"time,attr"`
160-
Skipped *junitSkipped `xml:"skipped,omitempty"`
161-
Failure *junitFailure `xml:"failure,omitempty"`
162-
Error *junitError `xml:"error,omitempty"`
163-
SystemOut *SystemOut `xml:"system-out,omitempty"`
164-
SystemErr *SystemErr `xml:"system-err,omitempty"`
149+
XMLName xml.Name `xml:"testcase"`
150+
Name string `xml:"name,attr"`
151+
Status string `xml:"status,attr"`
152+
Time string `xml:"time,attr"`
153+
Failure *junitFailure `xml:"failure,omitempty"`
154+
Error []*junitError
165155
}
166156

167157
type junitTestSuite struct {
168-
XMLName xml.Name `xml:"testsuite"`
169-
Name string `xml:"name,attr"`
170-
Tests int `xml:"tests,attr"`
171-
Failures int `xml:"failures,attr"`
172-
Errors int `xml:"errors,attr"`
173-
Disabled int `xml:"disabled,attr"`
174-
Skipped int `xml:"skipped,attr"`
175-
Time string `xml:"time,attr"`
176-
Hostname string `xml:"hostname,attr"`
177-
ID string `xml:"id,attr"`
178-
Package string `xml:"package,attr"`
179-
Timestamp time.Time `xml:"timestamp,attr"`
180-
SystemOut *SystemOut `xml:"system-out,omitempty"`
181-
SystemErr *SystemErr `xml:"system-err,omitempty"`
182-
Properties []*junitProperty `xml:"properties>property,omitempty"`
183-
TestCases []*TestCase
184-
}
185-
186-
func (ts *junitTestSuite) currentCase() *TestCase {
158+
XMLName xml.Name `xml:"testsuite"`
159+
Name string `xml:"name,attr"`
160+
Tests int `xml:"tests,attr"`
161+
Skipped int `xml:"skipped,attr"`
162+
Failures int `xml:"failures,attr"`
163+
Errors int `xml:"errors,attr"`
164+
Time string `xml:"time,attr"`
165+
TestCases []*TestCase
166+
}
167+
168+
func (ts *junitTestSuite) current() *TestCase {
187169
return ts.TestCases[len(ts.TestCases)-1]
188170
}
189171

190-
type junitTestSuites struct {
172+
type junitPackageSuite struct {
191173
XMLName xml.Name `xml:"testsuites"`
192174
Name string `xml:"name,attr"`
193175
Tests int `xml:"tests,attr"`
176+
Skipped int `xml:"skipped,attr"`
194177
Failures int `xml:"failures,attr"`
195178
Errors int `xml:"errors,attr"`
196-
Disabled int `xml:"disabled,attr"`
197179
Time string `xml:"time,attr"`
198180
TestSuites []*junitTestSuite
199181
}
200182

201-
func (ts *junitTestSuites) currentSuite() *junitTestSuite {
202-
return ts.TestSuites[len(ts.TestSuites)-1]
203-
}
204-
205-
func (j *junitFormatter) currentSuites() *junitTestSuites {
206-
return j.suites[len(j.suites)-1]
183+
func (j *junitFormatter) current() *junitTestSuite {
184+
return j.suite.TestSuites[len(j.suite.TestSuites)-1]
207185
}

0 commit comments

Comments
 (0)