Как стать автором
Обновить

Кодогенерация для создания go-sqlmock'ов

SQL-mock'и нужны, чтоб заменять собой подключения к настоящим БД в тестах. Действительно, очень неудобно держать сервер СУБД только для прогона тестов. Особенно если вы не пишете код работы с БД и она вам не нужна, или если вы — CI.



Используем SQL-mock'и


Для Golang существует достаточно популярная реализация go-sqlmock, которая позволяет симулировать поведение реальной БД на уровне sql/driver. Нужно только запрограммировать выдачу определенных результатов в ответ на определенные запросы, и mock готов. Вот как выглядит этот код:


    mock.ExpectQuery(`
INSERT INTO users (id, login, password, is_super) 
VALUES ($1, $2, $3, $4)
RETURNING created_at;`).WithArgs(
        driver.Value(1),
        driver.Value("user01"),
        driver.Value("second-P"),
        driver.Value(false),
    ).WillReturnRows(func() *sqlmock.Rows {
        rr := sqlmock.NewRows([]string{"created_at"})
        rr.AddRow(time.Unix(1580051896, 410421000))
        return rr
    }())

Но это двойная работа


Ведь сначала вы создаете структуры в БД и заливаете тестовые данные, а потом вынуждены повторить тоже самое в виде кода SQL-mock'а. И в дальнейшем нужно поддерживать этот код в соответствии с изменениями в БД. При этом возможно не точное повторение из-за человеческого фактора.


Kодогенератор может сделать за вас


Идея проста и реализована в opensource-проекте go-sqltest:


  • автор тестов оформляет их в виде специальных функций:

    func test<TESTNAME>(t *testing.T, conn *sql.DB) {
    // код теста, использующий подключение к БД conn
    }
  • и запускает с настоящей СУБД через кодогенератор sqlmockgen. Например, так:

    sqlmockgen -out=sql_test.go -db=postgresql://postgres:postgres@localhost:5432/test?sslmode=disable .
  • кодогенератор sqlmockgen перехватывает запросы тестов к БД и записывает их с ответами в виде sql-mock'ов и стандартных тестовых функций:

    func Test<TESTNAME>(t *testing.T) {
    // тест, использующий sql-mock вместо подключения к реальной БД
    }
  • все остальные могут запускать тесты стандартным образом и без реальной БД. Например, так:

    go test ./...
  • Profit!

Больше подробностей в README.


Детали реализации кодогенератора sqlmockgen


Для перехвата трафика между тестами и БД реализован специальный proxy sql/driver.


Драйвер не только пишет код sql-mock'а, но и одновременно настраивает один экземпляр. Очень удобно видеть рядом реальный вызов метода и этот же вызов в виде строки. Это пригодится при апгрейде версии go-sqlmock и, может быть, для какого-нибудь сценария в будущем.


Запуск тестов через кодогенератор сделан не очень изящно — переименование исходных файлов и вызов go test внутри, но другого способа я пока не нашел.


Заключение


Кодогенератор еще очень молодой и был использован только в одном проекте. Будет отлично, если он пригодится кому-нибудь еще.


И если отзывы помогут сделать его лучше.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.