adds more tests for multistep execution

Этот коммит содержится в:
gedi 2017-04-29 00:13:14 +03:00
родитель 703b40de76
коммит 5bfd57218a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 56604CDCCC201556
5 изменённых файлов: 158 добавлений и 27 удалений

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

@ -14,7 +14,7 @@ Feature: event stream formatter
""" """
Scenario: should process simple scenario Scenario: should process simple scenario
Given a feature path "features/load.feature:22" Given a feature path "features/load.feature:23"
When I run feature suite with formatter "events" When I run feature suite with formatter "events"
Then the following events should be fired: Then the following events should be fired:
""" """
@ -35,7 +35,7 @@ Feature: event stream formatter
""" """
Scenario: should process outline scenario Scenario: should process outline scenario
Given a feature path "features/load.feature:30" Given a feature path "features/load.feature:31"
When I run feature suite with formatter "events" When I run feature suite with formatter "events"
Then the following events should be fired: Then the following events should be fired:
""" """

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

@ -34,7 +34,6 @@ func TestProgressFormatterOutput(t *testing.T) {
}, },
} }
// var zeroDuration time.Duration
expected := ` expected := `
...F-.P-.UU.....F..P..U 23 ...F-.P-.UU.....F..P..U 23
@ -88,3 +87,113 @@ func trimAllLines(s string) string {
} }
return strings.Join(lines, "\n") return strings.Join(lines, "\n")
} }
var basicGherkinFeature = `
Feature: basic
Scenario: passing scenario
When step1
Then step2
`
func TestProgressFormatterWhenStepPanics(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var buf bytes.Buffer
w := colors.Uncolored(&buf)
r := runner{
fmt: progressFunc("progress", w),
features: []*feature{&feature{Feature: feat}},
initializer: func(s *Suite) {
s.Step(`^step1$`, func() error { return nil })
s.Step(`^step2$`, func() error { panic("omg") })
},
}
if !r.run() {
t.Fatal("the suite should have failed")
}
out := buf.String()
if idx := strings.Index(out, "github.com/DATA-DOG/godog/fmt_progress_test.go:116"); idx == -1 {
t.Fatal("expected to find panic stacktrace")
}
}
func TestProgressFormatterWithPassingMultisteps(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var buf bytes.Buffer
w := colors.Uncolored(&buf)
r := runner{
fmt: progressFunc("progress", w),
features: []*feature{&feature{Feature: feat}},
initializer: func(s *Suite) {
s.Step(`^sub1$`, func() error { return nil })
s.Step(`^sub-sub$`, func() error { return nil })
s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "step1"} })
s.Step(`^step1$`, func() error { return nil })
s.Step(`^step2$`, func() Steps { return Steps{"sub1", "sub2"} })
},
}
if r.run() {
t.Fatal("the suite should have passed")
}
}
func TestProgressFormatterWithFailingMultisteps(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var buf bytes.Buffer
w := colors.Uncolored(&buf)
r := runner{
fmt: progressFunc("progress", w),
features: []*feature{&feature{Feature: feat}},
initializer: func(s *Suite) {
s.Step(`^sub1$`, func() error { return nil })
s.Step(`^sub-sub$`, func() error { return fmt.Errorf("errored") })
s.Step(`^sub2$`, func() Steps { return Steps{"sub-sub", "sub1", "step1"} })
s.Step(`^step1$`, func() error { return nil })
s.Step(`^step2$`, func() Steps { return Steps{"sub1", "sub2"} })
},
}
if !r.run() {
t.Fatal("the suite should have failed")
}
}
func TestProgressFormatterWithPanicInMultistep(t *testing.T) {
feat, err := gherkin.ParseFeature(strings.NewReader(basicGherkinFeature))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var buf bytes.Buffer
w := colors.Uncolored(&buf)
r := runner{
fmt: progressFunc("progress", w),
features: []*feature{&feature{Feature: feat}},
initializer: func(s *Suite) {
s.Step(`^sub1$`, func() error { return nil })
s.Step(`^sub-sub$`, func() error { return nil })
s.Step(`^sub2$`, func() []string { return []string{"sub-sub", "sub1", "step1"} })
s.Step(`^step1$`, func() error { return nil })
s.Step(`^step2$`, func() []string { return []string{"sub1", "sub2"} })
},
}
if !r.run() {
t.Fatal("the suite should have failed")
}
}

2
run.go
Просмотреть файл

@ -54,7 +54,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
return return
} }
func (r *runner) run() (failed bool) { func (r *runner) run() bool {
suite := &Suite{ suite := &Suite{
fmt: r.fmt, fmt: r.fmt,
randomSeed: r.randomSeed, randomSeed: r.randomSeed,

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

@ -211,18 +211,7 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
match := s.matchStep(step) match := s.matchStep(step)
s.fmt.Defined(step, match) s.fmt.Defined(step, match)
// @TODO custom undefined err here to pass step text for snippet // user multistep definitions may panic
// @TODO user multistep definitions may panic
if s.maybeUndefined(match) {
s.fmt.Undefined(step)
return ErrUndefined
}
if prevStepErr != nil {
s.fmt.Skipped(step)
return nil
}
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
err = &traceError{ err = &traceError{
@ -230,6 +219,15 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
stack: callStack(), stack: callStack(),
} }
} }
if prevStepErr != nil {
return
}
if err == ErrUndefined {
return
}
switch err { switch err {
case nil: case nil:
s.fmt.Passed(step, match) s.fmt.Passed(step, match)
@ -245,6 +243,17 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
} }
}() }()
// @TODO custom undefined err here to pass step text for snippet
if s.maybeUndefined(match) {
s.fmt.Undefined(step)
return ErrUndefined
}
if prevStepErr != nil {
s.fmt.Skipped(step)
return nil
}
// run before step handlers // run before step handlers
for _, f := range s.beforeStepHandlers { for _, f := range s.beforeStepHandlers {
f(step) f(step)
@ -303,9 +312,15 @@ func (s *Suite) matchStepText(text string) *StepDef {
args = append(args, m) args = append(args, m)
} }
// @TODO copy step def // since we need to assign arguments
h.args = args // better to copy the step definition
return h return &StepDef{
args: args,
hv: h.hv,
Expr: h.Expr,
Handler: h.Handler,
nested: h.nested,
}
} }
} }
return nil return nil

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

@ -20,21 +20,28 @@ func TestMain(m *testing.M) {
format := "progress" // non verbose mode format := "progress" // non verbose mode
concurrency := 4 concurrency := 4
var specific bool
for _, arg := range os.Args[1:] { for _, arg := range os.Args[1:] {
if arg == "-test.v=true" { // go test transforms -v option - verbose mode if arg == "-test.v=true" { // go test transforms -v option - verbose mode
format = "pretty" format = "pretty"
concurrency = 1 concurrency = 1
break break
} }
if strings.Index(arg, "-test.run") == 0 {
specific = true
}
}
var status int
if !specific {
status = RunWithOptions("godog", func(s *Suite) {
SuiteContext(s)
}, Options{
Format: format, // pretty format for verbose mode, otherwise - progress
Paths: []string{"features"},
Concurrency: concurrency, // concurrency for verbose mode is 1
Randomize: time.Now().UnixNano(), // randomize scenario execution order
})
} }
status := RunWithOptions("godog", func(s *Suite) {
SuiteContext(s)
}, Options{
Format: format, // pretty format for verbose mode, otherwise - progress
Paths: []string{"features"},
Concurrency: concurrency, // concurrency for verbose mode is 1
Randomize: time.Now().UnixNano(), // randomize scenario execution order
})
if st := m.Run(); st > status { if st := m.Run(); st > status {
status = st status = st