less strict step registration
Этот коммит содержится в:
родитель
1f4ac0e8ec
коммит
c604d39ac5
5 изменённых файлов: 101 добавлений и 54 удалений
|
@ -7,12 +7,12 @@ Feature: suite events
|
||||||
Given I'm listening to suite events
|
Given I'm listening to suite events
|
||||||
|
|
||||||
Scenario: triggers before scenario event
|
Scenario: triggers before scenario event
|
||||||
Given a feature path "features/load_features.feature:6"
|
Given a feature path "features/load.feature:6"
|
||||||
When I run feature suite
|
When I run feature suite
|
||||||
Then there was event triggered before scenario "load features within path"
|
Then there was event triggered before scenario "load features within path"
|
||||||
|
|
||||||
Scenario: triggers appropriate events for a single scenario
|
Scenario: triggers appropriate events for a single scenario
|
||||||
Given a feature path "features/load_features.feature:6"
|
Given a feature path "features/load.feature:6"
|
||||||
When I run feature suite
|
When I run feature suite
|
||||||
Then these events had to be fired for a number of times:
|
Then these events had to be fired for a number of times:
|
||||||
| BeforeSuite | 1 |
|
| BeforeSuite | 1 |
|
||||||
|
@ -23,7 +23,7 @@ Feature: suite events
|
||||||
| AfterSuite | 1 |
|
| AfterSuite | 1 |
|
||||||
|
|
||||||
Scenario: triggers appropriate events whole feature
|
Scenario: triggers appropriate events whole feature
|
||||||
Given a feature path "features/load_features.feature"
|
Given a feature path "features/load.feature"
|
||||||
When I run feature suite
|
When I run feature suite
|
||||||
Then these events had to be fired for a number of times:
|
Then these events had to be fired for a number of times:
|
||||||
| BeforeSuite | 1 |
|
| BeforeSuite | 1 |
|
||||||
|
|
|
@ -6,31 +6,32 @@ 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 2 feature files:
|
Then I should have 3 feature files:
|
||||||
"""
|
"""
|
||||||
features/events.feature
|
features/events.feature
|
||||||
features/load_features.feature
|
features/load.feature
|
||||||
|
features/run.feature
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Scenario: load a specific feature file
|
Scenario: load a specific feature file
|
||||||
Given a feature path "features/load_features.feature"
|
Given a feature path "features/load.feature"
|
||||||
When I parse features
|
When I parse features
|
||||||
Then I should have 1 feature file:
|
Then I should have 1 feature file:
|
||||||
"""
|
"""
|
||||||
features/load_features.feature
|
features/load.feature
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Scenario: load a feature file with a specified scenario
|
Scenario: load a feature file with a specified scenario
|
||||||
Given a feature path "features/load_features.feature:6"
|
Given a feature path "features/load.feature:6"
|
||||||
When I parse features
|
When I parse features
|
||||||
Then I should have 1 scenario registered
|
Then I should have 1 scenario registered
|
||||||
|
|
||||||
Scenario: load a number of feature files
|
Scenario: load a number of feature files
|
||||||
Given a feature path "features/load_features.feature"
|
Given a feature path "features/load.feature"
|
||||||
And a feature path "features/events.feature"
|
And a feature path "features/events.feature"
|
||||||
When I parse features
|
When I parse features
|
||||||
Then I should have 2 feature files:
|
Then I should have 2 feature files:
|
||||||
"""
|
"""
|
||||||
features/load_features.feature
|
features/load.feature
|
||||||
features/events.feature
|
features/events.feature
|
||||||
"""
|
"""
|
18
features/run.feature
Обычный файл
18
features/run.feature
Обычный файл
|
@ -0,0 +1,18 @@
|
||||||
|
Feature: run features
|
||||||
|
In order to test application behavior
|
||||||
|
As a test suite
|
||||||
|
I need to be able to run features
|
||||||
|
|
||||||
|
Scenario: should run a normal feature
|
||||||
|
Given a feature "normal.feature" file:
|
||||||
|
"""
|
||||||
|
Feature: normal feature
|
||||||
|
|
||||||
|
Scenario: parse a scenario
|
||||||
|
Given a feature path "features/load.feature:6"
|
||||||
|
When I parse features
|
||||||
|
Then I should have 1 scenario registered
|
||||||
|
"""
|
||||||
|
When I run feature suite
|
||||||
|
Then the suite should have passed successfully
|
||||||
|
|
50
suite.go
50
suite.go
|
@ -11,12 +11,21 @@ import (
|
||||||
"github.com/DATA-DOG/godog/gherkin"
|
"github.com/DATA-DOG/godog/gherkin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Regexp is an unified type for regular expression
|
||||||
|
// it can be either a string or a *regexp.Regexp
|
||||||
|
type Regexp interface{}
|
||||||
|
|
||||||
|
// Handler is an unified type for a StepHandler
|
||||||
|
// interface satisfaction. It may be a function
|
||||||
|
// or a step handler
|
||||||
|
type Handler interface{}
|
||||||
|
|
||||||
// Status represents a step or scenario status
|
// Status represents a step or scenario status
|
||||||
type Status int
|
type Status int
|
||||||
|
|
||||||
// step or scenario status constants
|
// step or scenario status constants
|
||||||
const (
|
const (
|
||||||
invalid Status = iota
|
Invalid Status = iota
|
||||||
Passed
|
Passed
|
||||||
Failed
|
Failed
|
||||||
Undefined
|
Undefined
|
||||||
|
@ -71,7 +80,7 @@ type stepMatchHandler struct {
|
||||||
// Suite is an interface which allows various contexts
|
// Suite is an interface which allows various contexts
|
||||||
// to register step definitions and event handlers
|
// to register step definitions and event handlers
|
||||||
type Suite interface {
|
type Suite interface {
|
||||||
Step(expr *regexp.Regexp, h StepHandler)
|
Step(expr Regexp, h Handler)
|
||||||
// suite events
|
// suite events
|
||||||
BeforeSuite(h BeforeSuiteHandler)
|
BeforeSuite(h BeforeSuiteHandler)
|
||||||
BeforeScenario(h BeforeScenarioHandler)
|
BeforeScenario(h BeforeScenarioHandler)
|
||||||
|
@ -106,7 +115,10 @@ func New() *suite {
|
||||||
|
|
||||||
// Step allows to register a StepHandler in Godog
|
// Step allows to register a StepHandler in Godog
|
||||||
// feature suite, the handler will be applied to all
|
// feature suite, the handler will be applied to all
|
||||||
// steps matching the given regexp
|
// steps matching the given regexp expr
|
||||||
|
//
|
||||||
|
// It will panic if expr is not a valid regular expression
|
||||||
|
// or handler does not satisfy StepHandler interface
|
||||||
//
|
//
|
||||||
// Note that if there are two handlers which may match
|
// Note that if there are two handlers which may match
|
||||||
// the same step, then the only first matched handler
|
// the same step, then the only first matched handler
|
||||||
|
@ -114,10 +126,34 @@ func New() *suite {
|
||||||
//
|
//
|
||||||
// If none of the StepHandlers are matched, then a pending
|
// If none of the StepHandlers are matched, then a pending
|
||||||
// step error will be raised.
|
// step error will be raised.
|
||||||
func (s *suite) Step(expr *regexp.Regexp, h StepHandler) {
|
func (s *suite) Step(expr Regexp, h Handler) {
|
||||||
|
var handler StepHandler
|
||||||
|
var regex *regexp.Regexp
|
||||||
|
|
||||||
|
switch t := expr.(type) {
|
||||||
|
case *regexp.Regexp:
|
||||||
|
regex = t
|
||||||
|
case string:
|
||||||
|
regex = regexp.MustCompile(t)
|
||||||
|
case []byte:
|
||||||
|
regex = regexp.MustCompile(string(t))
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("expecting expr to be a *regexp.Regexp or a string, got type: %T", expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := h.(type) {
|
||||||
|
case StepHandlerFunc:
|
||||||
|
handler = t
|
||||||
|
case StepHandler:
|
||||||
|
handler = t
|
||||||
|
case func(...*Arg) error:
|
||||||
|
handler = StepHandlerFunc(t)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("expecting handler to satisfy StepHandler interface, got type: %T", h))
|
||||||
|
}
|
||||||
s.stepHandlers = append(s.stepHandlers, &stepMatchHandler{
|
s.stepHandlers = append(s.stepHandlers, &stepMatchHandler{
|
||||||
handler: h,
|
handler: handler,
|
||||||
expr: expr,
|
expr: regex,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +340,7 @@ func (s *suite) runFeature(f *gherkin.Feature) {
|
||||||
s.skipSteps(scenario.Steps)
|
s.skipSteps(scenario.Steps)
|
||||||
case status == Undefined:
|
case status == Undefined:
|
||||||
s.skipSteps(scenario.Steps)
|
s.skipSteps(scenario.Steps)
|
||||||
case status == Passed || status == invalid:
|
case status == Passed || status == Invalid:
|
||||||
status = s.runSteps(scenario.Steps)
|
status = s.runSteps(scenario.Steps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ package godog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/DATA-DOG/godog/gherkin"
|
"github.com/DATA-DOG/godog/gherkin"
|
||||||
|
@ -15,9 +13,8 @@ type firedEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type suiteFeature struct {
|
type suiteFeature struct {
|
||||||
testedSuite *suite
|
testedSuite *suite
|
||||||
events []*firedEvent
|
events []*firedEvent
|
||||||
tempFeatures []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) HandleBeforeScenario(*gherkin.Scenario) {
|
func (s *suiteFeature) HandleBeforeScenario(*gherkin.Scenario) {
|
||||||
|
@ -27,18 +24,10 @@ func (s *suiteFeature) HandleBeforeScenario(*gherkin.Scenario) {
|
||||||
SuiteContext(s.testedSuite)
|
SuiteContext(s.testedSuite)
|
||||||
// reset feature paths
|
// reset feature paths
|
||||||
cfg.paths = []string{}
|
cfg.paths = []string{}
|
||||||
s.tempFeatures = []string{}
|
|
||||||
// reset all fired events
|
// reset all fired events
|
||||||
s.events = []*firedEvent{}
|
s.events = []*firedEvent{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) HandleAfterScenario(*gherkin.Scenario) {
|
|
||||||
// remove temp files
|
|
||||||
for _, f := range s.tempFeatures {
|
|
||||||
os.Remove("/tmp/" + f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *suiteFeature) iAmListeningToSuiteEvents(args ...*Arg) error {
|
func (s *suiteFeature) iAmListeningToSuiteEvents(args ...*Arg) error {
|
||||||
s.testedSuite.BeforeSuite(BeforeSuiteHandlerFunc(func() {
|
s.testedSuite.BeforeSuite(BeforeSuiteHandlerFunc(func() {
|
||||||
s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
s.events = append(s.events, &firedEvent{"BeforeSuite", []interface{}{}})
|
||||||
|
@ -65,8 +54,13 @@ func (s *suiteFeature) aFailingStep(...*Arg) error {
|
||||||
return fmt.Errorf("intentional failure")
|
return fmt.Errorf("intentional failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) tempFeatureFile(args ...*Arg) error {
|
// parse a given feature file body as a feature
|
||||||
return nil
|
func (s *suiteFeature) aFeatureFile(args ...*Arg) error {
|
||||||
|
name := args[0].String()
|
||||||
|
body := args[1].PyString().Raw
|
||||||
|
feature, err := gherkin.Parse(strings.NewReader(body), name)
|
||||||
|
s.testedSuite.features = append(s.testedSuite.features, feature)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) featurePath(args ...*Arg) error {
|
func (s *suiteFeature) featurePath(args ...*Arg) error {
|
||||||
|
@ -79,6 +73,13 @@ func (s *suiteFeature) parseFeatures(args ...*Arg) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *suiteFeature) theSuitePassedSuccessfully(...*Arg) error {
|
||||||
|
if s.testedSuite.failed {
|
||||||
|
return fmt.Errorf("the feature suite has failed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *suiteFeature) iShouldHaveNumFeatureFiles(args ...*Arg) error {
|
func (s *suiteFeature) iShouldHaveNumFeatureFiles(args ...*Arg) error {
|
||||||
if len(s.testedSuite.features) != args[0].Int() {
|
if len(s.testedSuite.features) != args[0].Int() {
|
||||||
return fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.testedSuite.features))
|
return fmt.Errorf("expected %d features to be parsed, but have %d", args[0].Int(), len(s.testedSuite.features))
|
||||||
|
@ -177,28 +178,19 @@ func SuiteContext(g Suite) {
|
||||||
|
|
||||||
g.BeforeScenario(s)
|
g.BeforeScenario(s)
|
||||||
|
|
||||||
g.Step(regexp.MustCompile(`^a feature path "([^"]*)"$`), StepHandlerFunc(s.featurePath))
|
g.Step(`^a feature path "([^"]*)"$`, s.featurePath)
|
||||||
g.Step(regexp.MustCompile(`^I parse features$`), StepHandlerFunc(s.parseFeatures))
|
g.Step(`^I parse features$`, s.parseFeatures)
|
||||||
g.Step(regexp.MustCompile(`^I'm listening to suite events$`), StepHandlerFunc(s.iAmListeningToSuiteEvents))
|
g.Step(`^I'm listening to suite events$`, s.iAmListeningToSuiteEvents)
|
||||||
g.Step(regexp.MustCompile(`^I run feature suite$`), StepHandlerFunc(s.iRunFeatureSuite))
|
g.Step(`^I run feature suite$`, s.iRunFeatureSuite)
|
||||||
g.Step(regexp.MustCompile(`^feature "([^"]*)" file:$`), StepHandlerFunc(s.tempFeatureFile))
|
g.Step(`^a feature "([^"]*)" file:$`, s.aFeatureFile)
|
||||||
|
g.Step(`^the suite should have passed successfully$`, s.theSuitePassedSuccessfully)
|
||||||
|
|
||||||
g.Step(
|
g.Step(`^I should have ([\d]+) features? files?:$`, s.iShouldHaveNumFeatureFiles)
|
||||||
regexp.MustCompile(`^I should have ([\d]+) features? files?:$`),
|
g.Step(`^I should have ([\d]+) scenarios? registered$`, s.numScenariosRegistered)
|
||||||
StepHandlerFunc(s.iShouldHaveNumFeatureFiles))
|
g.Step(`^there (was|were) ([\d]+) "([^"]*)" events? fired$`, s.thereWereNumEventsFired)
|
||||||
g.Step(
|
g.Step(`^there was event triggered before scenario "([^"]*)"$`, s.thereWasEventTriggeredBeforeScenario)
|
||||||
regexp.MustCompile(`^I should have ([\d]+) scenarios? registered$`),
|
g.Step(`^these events had to be fired for a number of times:$`, s.theseEventsHadToBeFiredForNumberOfTimes)
|
||||||
StepHandlerFunc(s.numScenariosRegistered))
|
|
||||||
g.Step(
|
|
||||||
regexp.MustCompile(`^there (was|were) ([\d]+) "([^"]*)" events? fired$`),
|
|
||||||
StepHandlerFunc(s.thereWereNumEventsFired))
|
|
||||||
g.Step(
|
|
||||||
regexp.MustCompile(`^there was event triggered before scenario "([^"]*)"$`),
|
|
||||||
StepHandlerFunc(s.thereWasEventTriggeredBeforeScenario))
|
|
||||||
g.Step(
|
|
||||||
regexp.MustCompile(`^these events had to be fired for a number of times:$`),
|
|
||||||
StepHandlerFunc(s.theseEventsHadToBeFiredForNumberOfTimes))
|
|
||||||
|
|
||||||
g.Step(regexp.MustCompile(`^a failing step`), StepHandlerFunc(s.aFailingStep))
|
g.Step(`^a failing step`, s.aFailingStep)
|
||||||
g.Step(regexp.MustCompile(`^this step should fail`), StepHandlerFunc(s.aFailingStep))
|
g.Step(`^this step should fail`, s.aFailingStep)
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче