allow randomizing scenario order

Этот коммит содержится в:
Matthew Rothenberg 2017-04-24 21:10:55 -04:00
родитель 834d5841c7
коммит 4a754b26a5
3 изменённых файлов: 35 добавлений и 1 удалений

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

@ -13,6 +13,13 @@ type Options struct {
// Print step definitions found and exit // Print step definitions found and exit
ShowStepDefinitions bool ShowStepDefinitions bool
// Run scenarios in random order.
//
// This is especially helpful for detecting situations
// where you have state leaking between scenarios, which
// can cause flickering or fragile tests.
RandomOrder bool
// Stops on the first failure // Stops on the first failure
StopOnFailure bool StopOnFailure bool

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

@ -3,7 +3,9 @@ package godog
import ( import (
"fmt" "fmt"
"io" "io"
"math/rand"
"os" "os"
"time"
"github.com/DATA-DOG/godog/colors" "github.com/DATA-DOG/godog/colors"
) )
@ -11,6 +13,7 @@ import (
type initializer func(*Suite) type initializer func(*Suite)
type runner struct { type runner struct {
randomOrder bool
stopOnFailure bool stopOnFailure bool
features []*feature features []*feature
fmt Formatter fmt Formatter
@ -30,6 +33,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
} }
suite := &Suite{ suite := &Suite{
fmt: r.fmt, fmt: r.fmt,
randomOrder: r.randomOrder,
stopOnFailure: r.stopOnFailure, stopOnFailure: r.stopOnFailure,
features: []*feature{feat}, features: []*feature{feat},
} }
@ -54,6 +58,7 @@ func (r *runner) concurrent(rate int) (failed bool) {
func (r *runner) run() (failed bool) { func (r *runner) run() (failed bool) {
suite := &Suite{ suite := &Suite{
fmt: r.fmt, fmt: r.fmt,
randomOrder: r.randomOrder,
stopOnFailure: r.stopOnFailure, stopOnFailure: r.stopOnFailure,
features: r.features, features: r.features,
} }
@ -110,9 +115,16 @@ func RunWithOptions(suite string, contextInitializer func(suite *Suite), opt Opt
fmt: formatter(suite, output), fmt: formatter(suite, output),
initializer: contextInitializer, initializer: contextInitializer,
features: features, features: features,
randomOrder: opt.RandomOrder,
stopOnFailure: opt.StopOnFailure, stopOnFailure: opt.StopOnFailure,
} }
if opt.RandomOrder {
// TODO(mroth): allow for seed to be specified in options,
// and print it at the end of a run for replication purposes
rand.Seed(time.Now().UTC().UnixNano())
}
var failed bool var failed bool
if opt.Concurrency > 1 { if opt.Concurrency > 1 {
failed = r.concurrent(opt.Concurrency) failed = r.concurrent(opt.Concurrency)

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

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"math/rand"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -49,6 +50,7 @@ type Suite struct {
fmt Formatter fmt Formatter
failed bool failed bool
randomOrder bool
stopOnFailure bool stopOnFailure bool
// suite event handlers // suite event handlers
@ -330,7 +332,20 @@ func (s *Suite) runOutline(outline *gherkin.ScenarioOutline, b *gherkin.Backgrou
func (s *Suite) runFeature(f *feature) { func (s *Suite) runFeature(f *feature) {
s.fmt.Feature(f.Feature, f.Path, f.Content) s.fmt.Feature(f.Feature, f.Path, f.Content)
for _, scenario := range f.ScenarioDefinitions {
// make a local copy of the feature scenario defenitions,
// then shuffle it if we are randomizing scenarios
scenarios := make([]interface{}, len(f.ScenarioDefinitions))
if s.randomOrder {
perm := rand.Perm(len(f.ScenarioDefinitions))
for i, v := range perm {
scenarios[v] = f.ScenarioDefinitions[i]
}
} else {
copy(scenarios, f.ScenarioDefinitions)
}
for _, scenario := range scenarios {
var err error var err error
if f.Background != nil { if f.Background != nil {
s.fmt.Node(f.Background) s.fmt.Node(f.Background)