Типичное бизнес-приложение имеет МНОГО логики в запросах. Мы значительно уменьшаем охват тестированием и оставляем место для ошибок регрессии, если они не тестируются. Таким образом, издевательство над хранилищами БД - не лучший вариант. Вместо этого мы можем смоделировать саму базу данных и проверить, как мы работаем с ней на уровне SQL.
Ниже приведен пример кода с использованием DATA-DOG / go-sqlmock , но могут существовать и другие библиотеки, которые могут макетировать базы данных sql.
Прежде всего, нам нужно внедрить соединение SQL в наш код. GO sql connection - вводящее в заблуждение имя, и это фактически пул соединений, а не просто соединение с одной БД. Вот почему имеет смысл создать один *sql.DB
в корне вашей композиции и повторно использовать в коде, даже если вы не пишете тесты.
Пример ниже показывает, как макетировать веб-сервис.
В начале нам нужно создать новый обработчик с внедренным соединением:
// New creates new handler
func New(db *sql.DB) http.Handler {
return &handler{
db: db,
}
}
Код обработчика:
type handler struct {
db *sql.DB
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// some code that loads person name from database using id
}
Модульный тест того кода, который имитирует БД. Он использует stretchr / testify для утверждений:
func TestHandler(t *testing.T) {
db, sqlMock, _ := sqlmock.New()
rows := sqlmock.NewRows([]string{"name"}).AddRow("John")
// regex is used to match query
// assert that we execute SQL statement with parameter and return data
sqlMock.ExpectQuery(`select name from person where id \= \?`).WithArgs(42).WillReturnRows(rows)
defer db.Close()
sut := mypackage.New(db)
r, err := http.NewRequest(http.MethodGet, "https://example.com", nil)
require.NoError(t, err, fmt.Sprintf("Failed to create request: %v", err))
w := httptest.NewRecorder()
sut.ServeHTTP(w, r)
// make sure that all DB expectations were met
err = sqlMock.ExpectationsWereMet()
assert.NoError(t, err)
// other assertions that check DB data should be here
assert.Equal(t, http.StatusOK, w.Code)
}
Наш тест утверждает простой оператор SQL для БД. Но с go-sqlmock
можно протестировать все операции CRUD и транзакции базы данных.
Тест выше имеет еще одно слабое место. Мы проверили, что наш оператор SQL выполняется из кода, но мы не проверяли, работает ли он с нашей реальной БД. Эта проблема не может быть решена с помощью модульных тестов. Единственное решение - интеграционное тестирование с реальной БД.
Мы сейчас в лучшем положении. Наша бизнес-логика уже проверена в модульных тестах. Нам не нужно создавать множество интеграционных тестов, чтобы охватить различные сценарии и параметры, вместо этого нам нужно иметь только один тест на запрос для проверки синтаксиса SQL и соответствия нашей схеме БД.
Счастливого тестирования!