Add JUnit formatting support
Этот коммит содержится в:
родитель
ced06e6f22
коммит
d5b9497d7a
3 изменённых файлов: 323 добавлений и 0 удалений
139
fmt_junit.go
Обычный файл
139
fmt_junit.go
Обычный файл
|
@ -0,0 +1,139 @@
|
|||
package godog
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/adrianduke/godog/junit"
|
||||
gherkin "github.com/cucumber/gherkin-go"
|
||||
)
|
||||
|
||||
const JUnitResultsEnv = "JUNIT_RESULTS"
|
||||
|
||||
func init() {
|
||||
Format("junit", "Prints out in junit compatible xml format", &junitFormatter{
|
||||
JUnit: make(junit.JUnit, 0),
|
||||
})
|
||||
}
|
||||
|
||||
type junitFormatter struct {
|
||||
junit.JUnit
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Feature(feature *gherkin.Feature, path string) {
|
||||
testSuites := &junit.TestSuites{
|
||||
Name: feature.Name,
|
||||
TestSuites: make([]*junit.TestSuite, 0),
|
||||
}
|
||||
|
||||
j.JUnit = append(j.JUnit, testSuites)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Node(node interface{}) {
|
||||
testSuite := &junit.TestSuite{
|
||||
TestCases: make([]*junit.TestCase, 0),
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
switch t := node.(type) {
|
||||
case *gherkin.ScenarioOutline:
|
||||
testSuite.Name = t.Name
|
||||
case *gherkin.Scenario:
|
||||
testSuite.Name = t.Name
|
||||
case *gherkin.Background:
|
||||
testSuite.Name = "Background"
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuites.TestSuites = append(currentSuites.TestSuites, testSuite)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Failed(step *gherkin.Step, match *StepDef, err error) {
|
||||
testCase := &junit.TestCase{
|
||||
Name: step.Text,
|
||||
}
|
||||
|
||||
testCase.Failure = &junit.Failure{
|
||||
Contents: err.Error(),
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuites.Failures++
|
||||
currentSuite := currentSuites.CurrentSuite()
|
||||
currentSuite.Failures++
|
||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Passed(step *gherkin.Step, match *StepDef) {
|
||||
testCase := &junit.TestCase{
|
||||
Name: step.Text,
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuites.Tests++
|
||||
currentSuite := currentSuites.CurrentSuite()
|
||||
currentSuite.Tests++
|
||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Skipped(step *gherkin.Step) {
|
||||
testCase := &junit.TestCase{
|
||||
Name: step.Text,
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuite := currentSuites.CurrentSuite()
|
||||
currentSuite.Skipped++
|
||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Undefined(step *gherkin.Step) {
|
||||
testCase := &junit.TestCase{
|
||||
Name: step.Text,
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuites.Disabled++
|
||||
currentSuite := currentSuites.CurrentSuite()
|
||||
currentSuite.Disabled++
|
||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Pending(step *gherkin.Step, match *StepDef) {
|
||||
testCase := &junit.TestCase{
|
||||
Name: step.Text,
|
||||
}
|
||||
|
||||
testCase.Skipped = junit.Skipped{
|
||||
Contents: step.Text,
|
||||
}
|
||||
|
||||
currentSuites := j.JUnit.CurrentSuites()
|
||||
currentSuite := currentSuites.CurrentSuite()
|
||||
currentSuite.Skipped++
|
||||
currentSuite.TestCases = append(currentSuite.TestCases, testCase)
|
||||
}
|
||||
|
||||
func (j *junitFormatter) Summary() {
|
||||
var writer io.Writer
|
||||
if outputFilePath := os.Getenv(JUnitResultsEnv); outputFilePath != "" {
|
||||
outputFile, err := os.Create(outputFilePath)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
writer = io.Writer(outputFile)
|
||||
} else {
|
||||
writer = os.Stdout
|
||||
}
|
||||
|
||||
enc := xml.NewEncoder(writer)
|
||||
enc.Indent(" ", " ")
|
||||
if err := enc.Encode(j.JUnit); err != nil {
|
||||
fmt.Printf("error: %v\n", err)
|
||||
}
|
||||
}
|
91
junit/juint-4.xsd
Обычный файл
91
junit/juint-4.xsd
Обычный файл
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xs:element name="failure">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:attribute name="type" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="message" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="error">
|
||||
<xs:complexType mixed="true">
|
||||
<xs:attribute name="type" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="message" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="properties">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="property" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="property">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="value" type="xs:string" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="skipped" type="xs:string"/>
|
||||
<xs:element name="system-err" type="xs:string"/>
|
||||
<xs:element name="system-out" type="xs:string"/>
|
||||
|
||||
<xs:element name="testcase">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="assertions" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="classname" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="status" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="testsuite">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="properties" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="testcase" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element ref="system-out" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element ref="system-err" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||
<xs:attribute name="tests" type="xs:string" use="required"/>
|
||||
<xs:attribute name="failures" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="errors" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="disabled" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="skipped" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="timestamp" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="hostname" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="id" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="package" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:element name="testsuites">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element ref="testsuite" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="name" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="time" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="tests" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="failures" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="disabled" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="errors" type="xs:string" use="optional"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
|
||||
</xs:schema>
|
93
junit/structs.go
Обычный файл
93
junit/structs.go
Обычный файл
|
@ -0,0 +1,93 @@
|
|||
package junit
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Failure struct {
|
||||
Message string `xml:"message,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Contents string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
Message string `xml:"message,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Contents string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type Property struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
}
|
||||
|
||||
type Skipped struct {
|
||||
Contents string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type SystemErr struct {
|
||||
Contents string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type SystemOut struct {
|
||||
Contents string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
XMLName xml.Name `xml:"testcase"`
|
||||
Name string `xml:"name,attr"`
|
||||
Classname string `xml:"classname,attr"`
|
||||
Assertions string `xml:"assertions,attr"`
|
||||
Status string `xml:"status,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
Skipped *Skipped `xml:"skipped,omitempty"`
|
||||
Failure *Failure `xml:"failure,omitempty"`
|
||||
Error *Error `xml:"error,omitempty"`
|
||||
SystemOut *SystemOut `xml:"system-out,omitempty"`
|
||||
SystemErr *SystemErr `xml:"system-err,omitempty"`
|
||||
}
|
||||
|
||||
type TestSuite struct {
|
||||
XMLName xml.Name `xml:"testsuite"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests int `xml:"tests,attr"`
|
||||
Failures int `xml:"failures,attr"`
|
||||
Errors int `xml:"errors,attr"`
|
||||
Disabled int `xml:"disabled,attr"`
|
||||
Skipped int `xml:"skipped,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
Hostname string `xml:"hostname,attr"`
|
||||
ID string `xml:"id,attr"`
|
||||
Package string `xml:"package,attr"`
|
||||
Timestamp time.Time `xml:"timestamp,attr"`
|
||||
SystemOut *SystemOut `xml:"system-out,omitempty"`
|
||||
SystemErr *SystemErr `xml:"system-err,omitempty"`
|
||||
Properties []*Property `xml:"properties>property,omitempty"`
|
||||
TestCases []*TestCase
|
||||
}
|
||||
|
||||
func (ts *TestSuite) CurrentCase() *TestCase {
|
||||
return ts.TestCases[len(ts.TestCases)-1]
|
||||
}
|
||||
|
||||
type TestSuites struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests int `xml:"tests,attr"`
|
||||
Failures int `xml:"failures,attr"`
|
||||
Errors int `xml:"errors,attr"`
|
||||
Disabled int `xml:"disabled,attr"`
|
||||
Time string `xml:"time,attr"`
|
||||
TestSuites []*TestSuite
|
||||
}
|
||||
|
||||
func (ts *TestSuites) CurrentSuite() *TestSuite {
|
||||
return ts.TestSuites[len(ts.TestSuites)-1]
|
||||
}
|
||||
|
||||
type JUnit []*TestSuites
|
||||
|
||||
func (j JUnit) CurrentSuites() *TestSuites {
|
||||
return j[len(j)-1]
|
||||
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче