Skip to content

Commit

Permalink
Simplify testcases (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
hedhyw authored Jan 22, 2022
1 parent fbcebb7 commit 7e97ccb
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 102 deletions.
42 changes: 30 additions & 12 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Feature: Application command line tool
| -invalid | 1 | false |
```

**Then** this generator writes a [golang](internal/generator/examples/readme.feature.go) output:
**Then** this generator writes a [golang](internal/generator/examples/readme.feature_test.go) output (`gerkingen readme.feature > readme.feature_test.go`):

```go
func TestApplicationCommandLineTool(t *testing.T) {
Expand All @@ -50,21 +50,17 @@ func TestApplicationCommandLineTool(t *testing.T) {
"-invalid_1_false": {"-invalid", 1, false},
}

for name, tc := range testCases {
name, tc := name, tc
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
f.When("flag <flag> is provided", func() {

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
f.When("flag <flag> is provided", func() {

})
f.Then("usage should be printed <printed>", func() {
})
f.Then("usage should be printed <printed>", func() {

})
f.And("exit status should be <exit_status>", func() {
})
f.And("exit status should be <exit_status>", func() {

})
})
}
})
})
}
```
Expand All @@ -80,6 +76,26 @@ Feature: Application command line tool
And exit status should be 1
```

**Example** implementation:
```go
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
var exitStatus int
arguments := []string{}

f.When("flag <flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
f.Then("usage should be printed <printed>", func() {
var output string
output, exitStatus = runApp(t, arguments)
assert.Equal(t, tc.Printed, strings.Contains(output, "usage"))
})
f.And("exit status should be <exit_status>", func() {
assert.Equal(t, tc.ExitStatus, exitStatus)
})
})
```

## More advanced example

See [internal/app/app.feature](internal/app/app.feature) and [internal/app/app_test.go](internal/app/app_test.go).
Expand Down Expand Up @@ -125,6 +141,8 @@ Usage of gherkingen [FEATURE_FILE]:
print usage
-list
list internal templates
-package string
name of the generated package (default "generated_test")
-template string
template file (default "@/std.struct.v1.go.tmpl")
```
Expand Down
117 changes: 48 additions & 69 deletions internal/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,18 @@ func TestApplicationCommandLineTool(t *testing.T) {
"notfound.feature_raw_does not": {"notfound.feature", "raw", "does not"},
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
arguments := []string{}
f.When("<format> is given", func() {
arguments = append(arguments, "-format", tc.Format)
})
f.And("<feature> is provided", func() {
arguments = append(arguments, tc.Feature)
})
f.Then("the output should be generated", func() {
runApp(t, arguments, tc.Assertion == "does")
})
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
arguments := []string{}
f.When("<format> is given", func() {
arguments = append(arguments, "-format", tc.Format)
})
}
f.And("<feature> is provided", func() {
arguments = append(arguments, tc.Feature)
})
f.Then("the output should be generated", func() {
runApp(t, arguments, tc.Assertion == "does")
})
})
})

f.Scenario("User wants to see usage information", func(t *testing.T, f *bdd.Feature) {
Expand All @@ -77,19 +73,15 @@ func TestApplicationCommandLineTool(t *testing.T) {
"--help": {"--help"},
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
arguments := []string{}
f.When("<flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
f.Then("usage should be printed", func() {
runApp(t, arguments, true)
})
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
arguments := []string{}
f.When("<flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
}
f.Then("usage should be printed", func() {
runApp(t, arguments, true)
})
})
})

f.Scenario("User wants to list built-in templates", func(t *testing.T, f *bdd.Feature) {
Expand All @@ -101,19 +93,15 @@ func TestApplicationCommandLineTool(t *testing.T) {
"--list": {"--list"},
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
arguments := []string{}
f.When("<flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
f.Then("templates should be printed", func() {
runApp(t, arguments, true)
})
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
arguments := []string{}
f.When("<flag> is provided", func() {
arguments = append(arguments, tc.Flag)
})
}
f.Then("templates should be printed", func() {
runApp(t, arguments, true)
})
})
})

f.Scenario("User wants to use custom template", func(t *testing.T, f *bdd.Feature) {
Expand All @@ -127,22 +115,17 @@ func TestApplicationCommandLineTool(t *testing.T) {
"app.feature_@/std.struct.v1.go.tmpl": {"app.feature", "@/std.struct.v1.go.tmpl"},
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
arguments := []string{}
f.And("<template> is provided", func() {
arguments = append(arguments, "-template", tc.Template)
})
f.When("<feature> is provided", func() {
arguments = append(arguments, tc.Feature)
})
f.Then("the output should be generated", func() {
runApp(t, arguments, true)
})
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
arguments := []string{}
f.And("<template> is provided", func() {
arguments = append(arguments, "-template", tc.Template)
})
}
f.When("<feature> is provided", func() {
arguments = append(arguments, tc.Feature)
})
f.Then("the output should be generated", func() {
})
})
})

f.Scenario("User wants to set custom package", func(t *testing.T, f *bdd.Feature) {
Expand All @@ -155,21 +138,17 @@ func TestApplicationCommandLineTool(t *testing.T) {
"example_test": {"example_test"},
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
arguments := []string{}
f.When("<package> is provided", func() {
arguments = append(arguments, "-package", name, "app.feature")
})
f.Then("the output should contain <package>", func() {
out := runApp(t, arguments, true)
if !strings.Contains(out, tc.Package) {
t.Fatal(out)
}
})
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
arguments := []string{}
f.When("<package> is provided", func() {
arguments = append(arguments, "-package", tc.Package, "app.feature")
})
}
f.Then("the output should contain <package>", func() {
out := runApp(t, arguments, true)
if !strings.Contains(out, tc.Package) {
t.Fatal(out)
}
})
})
})
}
16 changes: 6 additions & 10 deletions internal/assets/std.struct.v1.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,13 @@ import (
{{- end }}
}

for name, tc := range testCases {
name, tc := name, tc

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
{{- range $Scenario.Steps }}
f.{{ .GoName }}({{ .GoValue }}, func() {

})
{{- end }}
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
{{- range $Scenario.Steps }}
f.{{ .GoName }}({{ .GoValue }}, func() {

})
}
{{- end }}
})
{{- else }}
{{- range $Scenario.Steps }}
f.{{ .GoName }}({{.GoValue}}, func() {
Expand Down
18 changes: 7 additions & 11 deletions internal/generator/examples/readme.feature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,17 @@ func TestApplicationCommandLineTool(t *testing.T) {
"-invalid_1_false": {"-invalid", 1, false},
}

for name, tc := range testCases {
name, tc := name, tc
f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
f.When("flag <flag> is provided", func() {

f.TestCase(name, tc, func(t *testing.T, f *bdd.Feature) {
f.When("flag <flag> is provided", func() {

})
f.Then("usage should be printed <printed>", func() {
})
f.Then("usage should be printed <printed>", func() {

})
f.And("exit status should be <exit_status>", func() {
})
f.And("exit status should be <exit_status>", func() {

})
})
}
})
})

}
41 changes: 41 additions & 0 deletions pkg/v1/bdd/bdd.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,47 @@ func (f *Feature) TestCase(name string, tc interface{}, fn func(t *testing.T, f
})
}

// TestCase defines a testcase block.
func (f *Feature) TestCases(testCases interface{}, fn interface{}) {
f.T.Helper()

if reflect.TypeOf(fn).Kind() != reflect.Func {
f.T.Fatalf("cannot call fn: %+v", fn)
}

callFn := func(t *testing.T, f *Feature, tc interface{}) {
t.Helper()

reflect.ValueOf(fn).Call([]reflect.Value{
reflect.ValueOf(t),
reflect.ValueOf(f),
reflect.ValueOf(tc),
})
}

rt := reflect.TypeOf(testCases)

if rt.Kind() != reflect.Map {
f.T.Fatalf("invalid testCases type: %s", rt.Kind())
}

iter := reflect.ValueOf(testCases).MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value()

if !v.CanInterface() {
f.T.Fatalf("testcase has unexported fields: %+v", v)
}

f.TestCase(k.String(), v.Interface(), func(t *testing.T, f *Feature) {
t.Helper()

callFn(t, f, v.Interface())
})
}
}

// And defines an and block.
func (f *Feature) And(and string, fn func()) {
f.T.Helper()
Expand Down
26 changes: 26 additions & 0 deletions pkg/v1/bdd/bdd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,32 @@ import (
"github.com/hedhyw/gherkingen/pkg/v1/bdd"
)

func TestBDDTestCases(t *testing.T) {
t.Run("ok", func(t *testing.T) {
f := bdd.NewFeature(t, "bdd")

type testCase struct {
Inc int
}

const expSum = 20
testCases := map[string]testCase{
"by_7": {7},
"by_13": {13},
}

var gotSum int

f.TestCases(testCases, func(t *testing.T, f *bdd.Feature, tc testCase) {
gotSum += tc.Inc
})

if gotSum != expSum {
t.Fatalf("Exp: %d, Got: %d", expSum, gotSum)
}
})
}

func TestBDD(t *testing.T) {
f := bdd.NewFeature(t, "bdd")

Expand Down

0 comments on commit 7e97ccb

Please sign in to comment.