Pull to refresh

Кодогенерация для создания 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 внутри, но другого способа я пока не нашел.


Заключение


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


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

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.