sqlmock is not matching query, but query is identical and log output shows the same

前端 未结 3 1856
南方客
南方客 2021-01-18 07:20

I\'m trying to write tests for some code using Gorm using sqlmock. I figured out writing tests for my insert function but now pulling my hair out trying to get an update wor

相关标签:
3条回答
  • 2021-01-18 07:33

    This is a strange solution but worked for me. Probably a bug in sqlmock. Duplicate your mockedRow variable and plug them in ExpectQuery.

    mockedRow := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "poolid"}).AddRow(1, time.Now(), time.Now(), "1")
    mockedRow2 := sqlmock.NewRows([]string{"id", "created_at", "updated_at", "poolid"}).AddRow(1, time.Now(), time.Now(), "1")
    
            // Mock the complete transaction
            mock.ExpectQuery(`SELECT * FROM "storage_pools"  WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1`).
                WithArgs(c.givenPool.PoolId).
                WillReturnRows(mockedRow)
    
            mock.ExpectQuery(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND "storage_pools"."id" = ? AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC`).
                WithArgs(1, c.givenPool.PoolId).
                WillReturnRows(mockedRow2)
    

    Alternatively you can create an array of mockedRow as follows:

    mockedRow := []*sqlmock.Rows{
    sqlmock.NewRows([]string{"id", "created_at", "updated_at", "poolid"}).AddRow(1, time.Now(), time.Now(), "1"),
    sqlmock.NewRows([]string{"id", "created_at", "updated_at", "poolid"}).AddRow(1, time.Now(), time.Now(), "1"),
    }
    And use it as WillReturnRows(mockedRow[0]) and WillReturnRows(mockedRow[1])
    
    0 讨论(0)
  • 2021-01-18 07:36

    Try this:

    mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "storage_pools" WHERE "storage_pools"."deleted_at" IS NULL AND ((poolid = ?)) ORDER BY "storage_pools"."id" ASC LIMIT 1`))
    

    Put your query into this function regexp.QuoteMeta().

    0 讨论(0)
  • 2021-01-18 07:48

    mock.ExpectExec() function does not perform simple strings comparison. Instead it uses input string as RegExp to match the query.

    Some characters in your SQL match string are reserved RegExp characters and should be escaped to match SQL.

    Your string should look like this after escaping:

    SELECT \* FROM "storage_pools" WHERE "storage_pools"\."deleted_at" IS NULL AND \(\(poolid \= \?\)\) ORDER BY "storage_pools"\."id" ASC LIMIT 1

    Hint: You can escape your string online using https://www.regex-escape.com/preg_quote-online.php or some other site

    Additional thought: Test with exact SQL match can be fragile without adding much extra value for exact SQL.

    Test can give you false positive result if anyone made harmless change in it like adding extra space character. From other side, full text match does not catch DB schema changes that are not compatible with SQL.

    I ended up with this setup for my projects:

    Run unit tests with mock.ExpectExec() with basic substrings like INSERT INTO history. That makes tests much less fragile. At the same time we are still checking a lot in this test to verify code execution flow:

    1. Number of SQL parameters
    2. Values of these SQL parameters
    3. Ensure that SQL command executed using mock.ExpectationsWereMet()

    On top of that we have to run integration tests for our SQL queries. That is the only way to make sure that our SQL are correct and up to date with latest DB changes.

    P.S. Avoid * in select. Be explicit with field names.

    Update1:

    Be careful with strings case. "SELECT" and "select" are two different strings.

    Some code snippets from my current project:

    // insert
    sqlMock.ExpectExec("INSERT INTO eeo").
            WithArgs("2018-12-31", "John Dow", "title"}).
            WillReturnResult(sqlmock.NewResult(mock.EeoID, 1))
    
    // select
    rows := sqlmock.NewRows([]string{"req_id", "state"})
    sqlMock.ExpectQuery("select").WithArgs(mock.CandidateID).WillReturnRows(rows)
    
    0 讨论(0)
提交回复
热议问题