Skip to content

Commit fee1391

Browse files
author
Vladimir Vivien
authored
Merge pull request #55 from vladimirvivien/table-driven-tests
Support for table-driven test representation
2 parents ea87ca9 + c4a197e commit fee1391

File tree

5 files changed

+164
-7
lines changed

5 files changed

+164
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/coverage.html
44
/coverage.out
55
.DS_Store
6+
.vscode

examples/table/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Table-Driven Tests
2+
This directory contains examples that show how the test framework can be used to define table-driven tests.

examples/table/table_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package table
18+
19+
import (
20+
"context"
21+
"math/rand"
22+
"os"
23+
"testing"
24+
"time"
25+
26+
"sigs.k8s.io/e2e-framework/pkg/env"
27+
"sigs.k8s.io/e2e-framework/pkg/envconf"
28+
"sigs.k8s.io/e2e-framework/pkg/features"
29+
)
30+
31+
var test = env.New()
32+
func TestMain(m *testing.M){
33+
// Setup the rand number source and a limit
34+
test.Setup(func(ctx context.Context, config *envconf.Config) (context.Context, error) {
35+
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
36+
return context.WithValue(context.WithValue(ctx, "limit", rand.Int31n(255)), "randsrc", rnd), nil
37+
})
38+
39+
// Don't forget to launch the package test
40+
os.Exit(test.Run(m))
41+
}
42+
43+
func TestTableDriven(t *testing.T) {
44+
// feature 1
45+
table0 := features.Table{
46+
{
47+
Name: "less than equal 64",
48+
Assessment: func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context {
49+
rnd := ctx.Value("randsrc").(*rand.Rand) // in real test, check asserted type
50+
lim := ctx.Value("limit").(int32) // check type assertion
51+
if rnd.Int31n(lim) > 64 {
52+
t.Log("limit should be less than 64")
53+
}
54+
return ctx
55+
},
56+
},
57+
{
58+
Name: "more than than equal 128",
59+
Assessment: func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context {
60+
rnd := ctx.Value("randsrc").(*rand.Rand) // in real test, check asserted type
61+
lim := ctx.Value("limit").(int32) // check type assertion
62+
if rnd.Int31n(lim) > 128 {
63+
t.Log("limit should be less than 128")
64+
}
65+
return ctx
66+
},
67+
},
68+
{
69+
Assessment: func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context {
70+
rnd := ctx.Value("randsrc").(*rand.Rand) // in real test, check asserted type
71+
lim := ctx.Value("limit").(int32) // check type assertion
72+
if rnd.Int31n(lim) > 256 {
73+
t.Log("limit should be less than 256")
74+
}
75+
return ctx
76+
},
77+
},
78+
}.Build("Random numbers").Feature()
79+
80+
// feature 2
81+
table1 := features.Table{
82+
{
83+
Name: "A simple feature",
84+
Assessment: func(ctx context.Context, t *testing.T, config *envconf.Config) context.Context {
85+
rnd := ctx.Value("randsrc").(*rand.Rand)
86+
if rnd.Int() > 100 {
87+
t.Log("this is a great number")
88+
}
89+
return ctx
90+
},
91+
},
92+
}
93+
94+
test.Test(t, table0, table1.Build().Feature() )
95+
}

pkg/env/env.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ package env
2121
import (
2222
"context"
2323
"fmt"
24+
"math/rand"
2425
"testing"
26+
"time"
2527

2628
log "k8s.io/klog/v2"
2729

@@ -42,6 +44,7 @@ type testEnv struct {
4244
ctx context.Context
4345
cfg *envconf.Config
4446
actions []action
47+
rnd rand.Source
4548
}
4649

4750
// New creates a test environment with no config attached.
@@ -89,6 +92,7 @@ func newTestEnv() *testEnv {
8992
return &testEnv{
9093
ctx: context.Background(),
9194
cfg: envconf.New(),
95+
rnd: rand.NewSource(time.Now().UnixNano()),
9296
}
9397
}
9498

@@ -190,7 +194,7 @@ func (e *testEnv) Test(t *testing.T, testFeatures ...types.Feature) {
190194
// execute each feature
191195
beforeFeatureActions := e.getBeforeFeatureActions()
192196
afterFeatureActions := e.getAfterFeatureActions()
193-
for _, feature := range testFeatures {
197+
for i, feature := range testFeatures {
194198
// execute beforeFeature actions
195199
for _, action := range beforeFeatureActions {
196200
if e.ctx, err = action.runWithFeature(e.ctx, e.cfg, deepCopyFeature(feature)); err != nil {
@@ -199,7 +203,11 @@ func (e *testEnv) Test(t *testing.T, testFeatures ...types.Feature) {
199203
}
200204

201205
// execute feature test
202-
e.ctx = e.execFeature(e.ctx, t, feature)
206+
featName := feature.Name()
207+
if featName == "" {
208+
featName = fmt.Sprintf("Feature-%d", i+1)
209+
}
210+
e.ctx = e.execFeature(e.ctx, t, featName, feature)
203211

204212
// execute beforeFeature actions
205213
for _, action := range afterFeatureActions {
@@ -304,9 +312,7 @@ func (e *testEnv) getFinishActions() []action {
304312
return e.getActionsByRole(roleFinish)
305313
}
306314

307-
func (e *testEnv) execFeature(ctx context.Context, t *testing.T, f types.Feature) context.Context {
308-
featName := f.Name()
309-
315+
func (e *testEnv) execFeature(ctx context.Context, t *testing.T, featName string, f types.Feature) context.Context {
310316
// feature-level subtest
311317
t.Run(featName, func(t *testing.T) {
312318
// skip feature which matches with --skip-feature
@@ -343,8 +349,12 @@ func (e *testEnv) execFeature(ctx context.Context, t *testing.T, f types.Feature
343349
// assessments run as feature/assessment sub level
344350
assessments := features.GetStepsByLevel(f.Steps(), types.LevelAssess)
345351

346-
for _, assess := range assessments {
347-
t.Run(assess.Name(), func(t *testing.T) {
352+
for i, assess := range assessments {
353+
assessName := assess.Name()
354+
if assessName == "" {
355+
assessName = fmt.Sprintf("Assessment-%d", i+1)
356+
}
357+
t.Run(assessName, func(t *testing.T) {
348358
// skip assessments which matches with --skip-assessments
349359
if e.cfg.SkipAssessmentRegex() != nil && e.cfg.SkipAssessmentRegex().MatchString(assess.Name()) {
350360
t.Skipf(`Skipping assessment "%s": name matched`, assess.Name())

pkg/features/table.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package features
18+
19+
import (
20+
"fmt"
21+
)
22+
23+
// Table provides a structure for table-driven tests.
24+
// Each entry in the table represents an executable assessment.
25+
type Table []struct {
26+
Name string
27+
Assessment Func
28+
}
29+
30+
// Build converts the defined test steps in the table
31+
// into a FeatureBuilder which can be used to add additional attributes
32+
// to the feature before it's exercised. Build takes an optional feature name
33+
// if omitted will be generated.
34+
func (table Table) Build(featureName ...string) *FeatureBuilder {
35+
var name string
36+
if len(featureName) > 0 {
37+
name = featureName[0]
38+
}
39+
f := New(name)
40+
for i, test := range table {
41+
if test.Name == "" {
42+
test.Name = fmt.Sprintf("Assessment-%d", i)
43+
}
44+
if test.Assessment != nil {
45+
f.Assess(test.Name, test.Assessment)
46+
}
47+
}
48+
return f
49+
}

0 commit comments

Comments
 (0)