initial tests for event stream formatter

Этот коммит содержится в:
gedi 2016-05-22 17:40:42 +03:00
родитель e71d596404
коммит c50c2dc368
5 изменённых файлов: 163 добавлений и 13 удалений

78
features/formatter/events.feature Обычный файл
Просмотреть файл

@ -0,0 +1,78 @@
Feature: event stream formatter
In order to have universal cucumber formatter
As a test suite
I need to be able to support event stream formatter
Scenario: should fire only suite events without any scenario
Given a feature path "features/load.feature:4"
When I run feature suite with formatter "events"
Then the following events should be fired:
"""
TestRunStarted
TestSource
TestRunFinished
"""
Scenario: should process simple scenario
Given a feature path "features/load.feature:21"
When I run feature suite with formatter "events"
Then the following events should be fired:
"""
TestRunStarted
TestSource
TestCaseStarted
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
TestCaseFinished
TestRunFinished
"""
Scenario: should process outline scenario
Given a feature path "features/load.feature:29"
When I run feature suite with formatter "events"
Then the following events should be fired:
"""
TestRunStarted
TestSource
TestCaseStarted
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
TestCaseFinished
TestCaseStarted
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
TestCaseFinished
TestCaseStarted
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
StepDefinitionFound
TestStepStarted
TestStepFinished
TestCaseFinished
TestRunFinished
"""

Просмотреть файл

@ -8,10 +8,11 @@ Savybė: užkrauti savybes
Scenarijus: savybių užkrovimas iš aplanko Scenarijus: savybių užkrovimas iš aplanko
Duota savybių aplankas "features" Duota savybių aplankas "features"
Kai aš išskaitau savybes Kai aš išskaitau savybes
Tada aš turėčiau turėti 7 savybių failus: Tada aš turėčiau turėti 8 savybių failus:
""" """
features/background.feature features/background.feature
features/events.feature features/events.feature
features/formatter/events.feature
features/lang.feature features/lang.feature
features/load.feature features/load.feature
features/outline.feature features/outline.feature

Просмотреть файл

@ -6,10 +6,11 @@ Feature: load features
Scenario: load features within path Scenario: load features within path
Given a feature path "features" Given a feature path "features"
When I parse features When I parse features
Then I should have 7 feature files: Then I should have 8 feature files:
""" """
features/background.feature features/background.feature
features/events.feature features/events.feature
features/formatter/events.feature
features/lang.feature features/lang.feature
features/load.feature features/load.feature
features/outline.feature features/outline.feature

Просмотреть файл

@ -1,12 +1,27 @@
package godog package godog
import "github.com/DATA-DOG/godog/gherkin" import (
"io"
"time"
"github.com/DATA-DOG/godog/gherkin"
)
type testFormatter struct { type testFormatter struct {
basefmt basefmt
scenarios []interface{} scenarios []interface{}
} }
func testFormatterFunc(out io.Writer) Formatter {
return &testFormatter{
basefmt: basefmt{
started: time.Now(),
indent: 2,
out: out,
},
}
}
func (f *testFormatter) Node(node interface{}) { func (f *testFormatter) Node(node interface{}) {
f.basefmt.Node(node) f.basefmt.Node(node)
switch t := node.(type) { switch t := node.(type) {

Просмотреть файл

@ -1,6 +1,8 @@
package godog package godog
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -18,6 +20,7 @@ func SuiteContext(s *Suite) {
s.Step(`^I parse features$`, c.parseFeatures) s.Step(`^I parse features$`, c.parseFeatures)
s.Step(`^I'm listening to suite events$`, c.iAmListeningToSuiteEvents) s.Step(`^I'm listening to suite events$`, c.iAmListeningToSuiteEvents)
s.Step(`^I run feature suite$`, c.iRunFeatureSuite) s.Step(`^I run feature suite$`, c.iRunFeatureSuite)
s.Step(`^I run feature suite with formatter "([^"]*)"$`, c.iRunFeatureSuiteWithFormatter)
s.Step(`^a feature "([^"]*)" file:$`, c.aFeatureFile) s.Step(`^a feature "([^"]*)" file:$`, c.aFeatureFile)
s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave) s.Step(`^the suite should have (passed|failed)$`, c.theSuiteShouldHave)
@ -32,6 +35,9 @@ func SuiteContext(s *Suite) {
s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave) s.Step(`^the following steps? should be (passed|failed|skipped|undefined|pending):`, c.followingStepsShouldHave)
s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe) s.Step(`^the undefined step snippets should be:$`, c.theUndefinedStepSnippetsShouldBe)
// event stream
s.Step(`^the following events should be fired:$`, c.thereShouldBeEventsFired)
// lt // lt
s.Step(`^savybių aplankas "([^"]*)"$`, c.featurePath) s.Step(`^savybių aplankas "([^"]*)"$`, c.featurePath)
s.Step(`^aš išskaitau savybes$`, c.parseFeatures) s.Step(`^aš išskaitau savybes$`, c.parseFeatures)
@ -54,20 +60,59 @@ type suiteContext struct {
paths []string paths []string
testedSuite *Suite testedSuite *Suite
events []*firedEvent events []*firedEvent
fmt *testFormatter out bytes.Buffer
} }
func (s *suiteContext) ResetBeforeEachScenario(interface{}) { func (s *suiteContext) ResetBeforeEachScenario(interface{}) {
// reset whole suite with the state // reset whole suite with the state
s.fmt = &testFormatter{} s.out.Reset()
s.paths = []string{} s.paths = []string{}
s.testedSuite = &Suite{fmt: s.fmt} s.testedSuite = &Suite{}
// our tested suite will have the same context registered // our tested suite will have the same context registered
SuiteContext(s.testedSuite) SuiteContext(s.testedSuite)
// reset all fired events // reset all fired events
s.events = []*firedEvent{} s.events = []*firedEvent{}
} }
func (s *suiteContext) iRunFeatureSuiteWithFormatter(name string) error {
f, err := findFmt(name)
if err != nil {
return err
}
s.testedSuite.fmt = f(&s.out)
if err := s.parseFeatures(); err != nil {
return err
}
s.testedSuite.run()
s.testedSuite.fmt.Summary()
return nil
}
func (s *suiteContext) thereShouldBeEventsFired(doc *gherkin.DocString) error {
actual := strings.Split(strings.TrimSpace(s.out.String()), "\n")
expect := strings.Split(strings.TrimSpace(doc.Content), "\n")
if len(expect) != len(actual) {
return fmt.Errorf("expected %d events, but got %d", len(expect), len(actual))
}
type ev struct {
Event string
}
for i, event := range actual {
exp := strings.TrimSpace(expect[i])
var act ev
if err := json.Unmarshal([]byte(event), &act); err != nil {
return fmt.Errorf("failed to read event data: %v", err)
}
if act.Event != exp {
return fmt.Errorf(`expected event: "%s" at position: %d, but actual was "%s"`, exp, i, act.Event)
}
}
return nil
}
func (s *suiteContext) cleanupSnippet(snip string) string { func (s *suiteContext) cleanupSnippet(snip string) string {
lines := strings.Split(strings.TrimSpace(snip), "\n") lines := strings.Split(strings.TrimSpace(snip), "\n")
for i := 0; i < len(lines); i++ { for i := 0; i < len(lines); i++ {
@ -77,10 +122,14 @@ func (s *suiteContext) cleanupSnippet(snip string) string {
} }
func (s *suiteContext) theUndefinedStepSnippetsShouldBe(body *gherkin.DocString) error { func (s *suiteContext) theUndefinedStepSnippetsShouldBe(body *gherkin.DocString) error {
actual := s.cleanupSnippet(s.fmt.snippets()) f, ok := s.testedSuite.fmt.(*testFormatter)
if !ok {
return fmt.Errorf("this step requires testFormatter, but there is: %T", s.testedSuite.fmt)
}
actual := s.cleanupSnippet(f.snippets())
expected := s.cleanupSnippet(body.Content) expected := s.cleanupSnippet(body.Content)
if actual != expected { if actual != expected {
return fmt.Errorf("snippets do not match actual: %s", s.fmt.snippets()) return fmt.Errorf("snippets do not match actual: %s", f.snippets())
} }
return nil return nil
} }
@ -89,25 +138,29 @@ func (s *suiteContext) followingStepsShouldHave(status string, steps *gherkin.Do
var expected = strings.Split(steps.Content, "\n") var expected = strings.Split(steps.Content, "\n")
var actual, unmatched, matched []string var actual, unmatched, matched []string
f, ok := s.testedSuite.fmt.(*testFormatter)
if !ok {
return fmt.Errorf("this step requires testFormatter, but there is: %T", s.testedSuite.fmt)
}
switch status { switch status {
case "passed": case "passed":
for _, st := range s.fmt.passed { for _, st := range f.passed {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
case "failed": case "failed":
for _, st := range s.fmt.failed { for _, st := range f.failed {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
case "skipped": case "skipped":
for _, st := range s.fmt.skipped { for _, st := range f.skipped {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
case "undefined": case "undefined":
for _, st := range s.fmt.undefined { for _, st := range f.undefined {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
case "pending": case "pending":
for _, st := range s.fmt.pending { for _, st := range f.pending {
actual = append(actual, st.step.Text) actual = append(actual, st.step.Text)
} }
default: default:
@ -231,7 +284,9 @@ func (s *suiteContext) iRunFeatureSuite() error {
if err := s.parseFeatures(); err != nil { if err := s.parseFeatures(); err != nil {
return err return err
} }
s.testedSuite.fmt = testFormatterFunc(&s.out)
s.testedSuite.run() s.testedSuite.run()
s.testedSuite.fmt.Summary()
return nil return nil
} }