Skip to content

testing: add -shuffle and -shuffleseed to shuffle tests #28592

@cristaloleg

Description

@cristaloleg

This is a revive of #10655

Motivation

Consider the following code & corresponding tests:

package pkg

// build and cache regexp, reuse between clients
var re *regexp.Regexp

type Client struct {
	// ...
}

func NewClient(pattern string) *Client {
	if re == nil {
		re = regexp.MustCompile(pattern)
	}
	return &Client{
		// ...
	}
}

func (c *Client) HasPattern(s string) error {
	if !re.MatchString(s) {
		return errors.New("meh, incorrect param")
	}
	return nil
}
package pkg

func TestFoo(t *testing.T) {
	s := NewClient("^foo.*")
	err := s.HasPattern("foo123")
	if err != nil {
		t.Errorf("expected to pass")
	}
}

func TestFooBar(t *testing.T) {
	s := NewClient("^foobar.*")
	err := s.HasPattern("foobar1123")
	if err != nil {
		t.Errorf("expected to pass")
	}
}

Those tests pass, everything looks fine, but they're order dependent. Running them in another order will fail.

To prevent such hidden and hard to debug mistakes we need to make the order of test random for each test build.

Current workarounds

  1. Manual ordering of tests.
  2. Boilerplate code to specify the order of tests.
  3. For table-driven tests we can use a map instead of slice, ex:
func TestSomething(t *testing.T) {
	testCases := map[name]struct{
		a,b int64
		res int64
	}{
		“simple case”: {1, 2, 3},
		“less simple”: {3, 3, 23},
	}

	// due to behaviour of map test cases will be 
	// in a different order for each run
	// but this solution is limited and not suitable for test funcs
	// aka `func TestXXX(t *testing.T)`
	for name, tc := range testCases {
		t.Logf(“test: %s”, name)

		res := foo(tc.a, tc.b)
		if res != tc.res {
			t.Errorf(“want %v, got %v, res, tc.res)
		}
	}
}

Possible solution

We need to specify a test run to execute tests with a random/desired order:

  1. -shuffle to run tests with a random order (used random seed may or should be printed to output depending or not on a -v flag).
  2. -seed <int> to specify a user-defined seed to have an ability repeat a failed build.

Open questions

  1. Should we randomize order of benchmarks and examples? (looks like not)
  2. This makes test runs 'flaky' but this helps to reveal possible implementation caveats.
  3. This might not happen for 1.12 'cause proposal is submitted too late.

PS. if/when it will be accepted - will be happy to work on it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions