Skip to content

proposal: doc: add table driven pattern for mocks #559

@posener

Description

@posener

Hi

It took us a while to find this really easy to use pattern for table driven tests with mocks.
The idea is that each test contains a prepare function that gets the mock objects and runs the test case logic.

Before that, we had lots of if statements in the test itself, and here we moved the logic to the table so it is much easier to read and understand.

Here it is, and I suggest maybe add it to the docs/readme?

func TestUnit_Func1(t *testing.T) {
	t.Parallel()
	tests = []struct{
		name string // name for test case
		arg1 string
		arg2 int
		want *Result
		wantError bool
		prepare func(*client1.Mock, *client2.Mock)
	}{
		{
			// test 1
			name: "simple input",
			arg1: "a",
			arg2: 1,
			want: &Result{Concat: "a1"},
			wantErr: false,
			prepare: func(c1 *client1.Mock, c2 *client2.Mock) {
				// here we prepare the mocks that the unit are dependent on.
				c1.On("Check", mock.Anything).Return(nil).Once()
				c2.On("Add", "a", 1).Return("a1", nil).Once()
				// ...
			},
		},
		{
			// test 2
		},
		// ...
	}
	
	for _, tt := range tests {
		// constract a unique name for the test, from the function arguments
		name := fmt.Sprintf("%s,%d", tt.arg1, tt.arg2)
                tt := tt
		
		// run a sub-test:
		t.Run(name, func(t *testing.T) {
                        t.Parallel()
			// create mocks
			c1 := new(client1.Mock)
			c2 := new(client2.Mock)
			
			// prepare the mocks:
			if tt.prepare != nil {
				tt.prepare(c1, c2)
			}
			
			// create unit
			u, err := New(c1, c2)
			require.Nil(t, err)
			
			// run the tested function
			got, err := u.Func1(tt.arg1, tt.arg2)
			
			// assert results expectations
			if tt.wantErr {
				assert.NotNil(t, err)
			} else {
				assert.Nil(t, err)
				assert.Equal(t, want, got) // notice the go convention: want is first argument, got is the second argument
			}
			
			// assert that the mocks were called correctly.
			c1.AssertExpectations(t)
			c2.AssertExpectations(t)
		})
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions