Модульні (unit) тести в Go

Юніт або ще модульні тести. Такі тести передбачають тестування одного конкретного функціоналу, якоїсь маленької частини програми, як правило це функції. За звичай на функцію пишуть як правило декілька сценаріїв (тест кейсів).

Для прикладу будем використовувати REST-API застосунок з цього прикладу tests.

Файли з тестами потрібно називаються *_test.go а методи тестів Test*. Ось приклад validate_test.go і метод TestValidate.

У нашому зразку є один хендлер user.go, що має метод validate для валідації вхідних даних при реєстрації нового користувача.

type createUserRequest struct {
	Name  string `json:"name"`
	Email string `json:"email"`
	Phone string `json:"phone"`
}

func (r *createUserRequest) validate() (bool, error) {
	if len(r.Name) < 3 {
		return false, fmt.Errorf("%s", "Bad request, short user name")
	}

	if len(r.Phone) < 9 {
		return false, fmt.Errorf("%s", "Bad request, short user phone")
	}

	_, err := mail.ParseAddress(r.Email)
	if err != nil {
		return false, fmt.Errorf("%s", "Bad request, wrong user email")
	}

	return true, nil
}

В GO є пакет для написання тестів testing, йото ми будем використовувати. Для валідації результату ми будем використовувати пакет assert.

Ми можем створиту нашу структуру яку потрібно провалідувати, заповнивши її певними тестовими даними і пізніше на ній викликати метод validate() який ми тестуєм, і пізніше перевірити результат її роботи.

createUserRequest{
Name:  "tesr",
Email: "test@tt.com",
Phone: "1234567890",
}

Ми можемо створити багато таких структур з різними вхідними даними, і на кожну структуру зробити свою окрему тест функцію. Але замість того щоб на кожний тест кейс писати новий метод, в GO можна використовувати підхід табличних тестів (Data-Driven Testing).

Нам потрібно створити слайс з тесткейсами які ми будем перебирати в циклі. Пропоную створити таку структуру для тест кейсу. Де name це назва нашого тесткейсу, request структура яку наш метод повинна провалідувати, ok це результат роботи методу, err це помилка яку може повернути наш метод.

testCases := []struct {
		name    string
		request createUserRequest
		ok      bool
		err     error
	}

Заповниши тестовими даними наші структури і очікуваними результатами які має повернути нам метод validate(), ми отримуєм такі тест кейси.

testCases := []struct {
		name    string
		request createUserRequest
		ok      bool
		err     error
	}{
		{
			name: "Ok",
			request: createUserRequest{
				Name:  "tesr",
				Email: "test@tt.com",
				Phone: "1234567890",
			},
			ok: true,
		},
		{
			name: "Bad request, short user name",
			request: createUserRequest{
				Name:  "",
				Email: "test@tt.com",
				Phone: "1234567890",
			},
			ok:  false,
			err: fmt.Errorf("%s", "Bad request, short user name"),
		},
		{
			name: "Bad request, wrong user email",
			request: createUserRequest{
				Name:  "test",
				Email: "test@com",
				Phone: "1234567890",
			},
			ok:  false,
			err: fmt.Errorf("%s", "Bad request, wrong user email"),
		},
		{
			name: "Bad request, short user phone",
			request: createUserRequest{
				Name:  "test",
				Email: "test@tt.com",
				Phone: "123",
			},
			ok:  false,
			err: fmt.Errorf("%s", "Bad request, short user phone"),
		},
	}

Тепер напишемо цикл в якому пройдемся по наши тесткейсам

for i := range testCases {
		testCase := testCases[i]
		t.Run(testCase.name, func(t *testing.T) {
			ok, err := testCase.request.validate()

			if !ok {
				assert.Equal(t, err, testCase.err)
			} else {
				assert.NoError(t, err)
			}

		})
	}

Для валідації роботи нашого методу будем використовувати функції Equal() і NoError() з пакету assert. Приклад усьго коду знаходиться у файлі validate_test.go.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься.