Модульный тест Go — не удалось сопоставить фактический sql с ожидаемым регулярным выражением, издеваясь над gorm с помощью go-sqlmock?

# #unit-testing #go #mocking #go-gorm #go-sqlmock

Вопрос:

При модульном тестировании я издеваюсь над гормом, используя sqlmock. Но при запуске все начальные настройки работают нормально, но при совпадении фактического запроса и тестового запроса возникают ошибки. Я привел ниже все коды.

пользователь.иди

 func (r *users) GetUserByID(userID uint) (*domain.User, *errors.RestErr) {
    var resp domain.User

    res := r.DB.Model(amp;domain.User{}).Where("id = ?", userID).First(amp;resp)

    if res.RowsAffected == 0 {
        logger.Error("error occurred when getting user by user id", res.Error)
        return nil, errors.NewNotFoundError(errors.ErrRecordNotFound)
    }

    return amp;resp, nil
}
 

Издеваться

user_test.go

 type Suite struct {
    suite.Suite
    DB         *gorm.DB
    mock       sqlmock.Sqlmock
    db         *sql.DB
    err        error
    repository repository.IUsers
}

func (s *Suite) SetupSuite() {
    s.db, s.mock, s.err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))

    require.NoError(s.T(), s.err)

    dialector := mysql.New(mysql.Config{
        DSN:                       "sqlmock_db_0",
        DriverName:                "mysql",
        Conn:                      s.db,
        SkipInitializeWithVersion: true,
    })

    s.DB, s.err = gorm.Open(dialector, amp;gorm.Config{})

    require.NoError(s.T(), s.err)
    s.repository = impl.NewMySqlUsersRepository(s.DB)
}

func (s *Suite) AfterTest(_, _ string) {
    require.NoError(s.T(), s.mock.ExpectationsWereMet())
}

func TestInit(t *testing.T) {
    suite.Run(t, new(Suite))
}

// .................Start Testing....................

func (s *Suite) Test_repository_Get() {
    var (
        id        = uint(1)
        user_name = "user-name"
        fast_name = "fast-name"
    )

    s.mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "users" WHERE (id = $1) ORDER BY "users"."id" LIMIT 1`)).
        WithArgs(uint(id)).
        WillReturnRows(sqlmock.NewRows([]string{"id", "user_name", "fast_name"}).
            AddRow(uint(id), user_name, fast_name))

    res, _ := s.repository.GetUserByID(uint(id))
    require.Nil(s.T(), deep.Equal(amp;domain.User{ID: uint(id), UserName: user_name, LastName: fast_name}, res))
}
 

когда я выполняю res, _ := s.repository.GetUserByID(uint(id)) эту строку, она переходит в файл user.go. Здесь в строке запроса sql появляется ошибка, подобная приведенной ниже .

 actual sql: "SELECT * FROM `users` WHERE id = ? ORDER BY `users`.`id` LIMIT 1" 
does not equal to expected "SELECT * FROM "users" WHERE (id = $1) ORDER BY "users"."id" LIMIT 1"


=> expecting Query, QueryContext or QueryRow which:
     - matches sql: 'SELECT * FROM "users" WHERE (id = $1) ORDER BY "users"."id" LIMIT 1'
     - is with arguments:
                0 - 1
     - should return rows:
                row 0 - [1 user-name fast-name]
 

В чем здесь проблема?

Комментарии:

1. это "SELECT * FROM `users` WHERE id = ? ORDER BY `users`.`id` ОГРАНИЧЕНИЕ 1″` не равно "SELECT * FROM "users" WHERE (id = $1) ORDER BY "users"."id" LIMIT 1" . Где первый запрос-это то, что драйвер макета получил в качестве входных данных от gorm (т. е. actual sql ), а второй запрос-то, что вы написали как ожидание. Ваши ожидания ошибочны.

2. mysql просто не использует заполнитель индексированного запроса, AFAIK.

3. Тогда что я должен здесь написать?

Ответ №1:

Основная проблема, вызванная здесь sql-запросом. Для получения товара нам здесь не понадобится полный запрос. Горм автоматически сгенерирует это. нужно только пройти

 "SELECT(.*)"
 

Я нашел это в сообщении в блоге на Medium.
Здесь вы можете найти подробную информацию

Приведенный ниже код работает нормально

 func (s *Suite) Test_repository_GetUserByID() {
var (
    id         = uint(1)
    user_name  = "user-name"
    first_name = "first-name"
)
s.mock.ExpectQuery("SELECT(.*)").
    WithArgs(id).
    WillReturnRows(sqlmock.NewRows([]string{"id", "user_name", "first_name"}).
        AddRow(uint(id), user_name, first_name))

 res, _ := s.repository.GetUserByID(uint(id))
 require.Nil(s.T(), deep.Equal(amp;domain.User{ID: uint(id), UserName: user_name, FirstName: first_name}, res))
 }
 

Комментарии:

1. говоря по-дружески, это скорее обходной путь, чем решение. Это работает ! мы согласны с этим, но я чувствую, что вы упустили главное. Так что на всякий случай я хочу поделиться с вами этой маленькой ссылкой go-database-sql.org/… что, я надеюсь, откроет вам глаза на первоначальный вопрос