DATA-DOG / go-sqlmock

Sql mock driver for golang to test database interactions
Other
6.05k stars 406 forks source link

Provide unordered args matching #207

Closed franklingu closed 4 years ago

franklingu commented 4 years ago

Specifically, I am referring to this function: https://github.com/DATA-DOG/go-sqlmock/blob/master/expectations_go18.go#L30

When I am using gorm to update like (http://gorm.io/docs/update.html):

// Update multiple attributes with `map`, will only update those changed fields
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
//// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

the order of update is not fixed. however, based on sqlmock current matching strategy, I cannot just assert that I updated name+age+actived and order is not important here.

Apologiz commented 4 years ago

I agree, I have the same problem. Parameters are collected dynamically and their order is not known in advance.

There is an option to add support for sql.Named args for such a case.

What do you think of it?

P.S. https://golang.org/src/database/sql/sql.go line 1588. Method returns args without names...

Apologiz commented 4 years ago

GORM v1.9.11 doesn't support sql.Names args. I did PR with it support :)

DATA-DOG/go-sqlmock: https://github.com/DATA-DOG/go-sqlmock/pull/208 jinzhu/gorm: https://github.com/jinzhu/gorm/pull/2783

Apologiz commented 4 years ago

@franklingu, by the way, your problem may be solved easier. You can try it: sqlmock.ExpectExec("UPDATE `table_name` SET (.+) WHERE (.+)")

franklingu commented 4 years ago

@franklingu, by the way, your problem may be solved easier. You can try it: sqlmock.ExpectExec("UPDATE table_name SET (.+) WHERE (.+)")

that is make the expectation loose enough so that test will pass right? what if I actually want to assert those args?

Apologiz commented 4 years ago

that is make the expectation loose enough so that test will pass right? what if I actually want to assert those args?

You can use WithArgs method in query chain, but as you already know, the sequence of arguments may be random.

sqlmock.ExpectExec(...).WithArgs(...).WillReturnResult(...)

l3pp4rd commented 4 years ago

yes, with randomness, we cannot help (go maps are unordered). unless you would use a custom Argument interface implementation and do the magic there in order to somehow match them

wblech commented 3 years ago

For this problem I use this type Argument from the docs https://pkg.go.dev/github.com/DATA-DOG/go-sqlmock#Argument

You can check using the method Match

type VerifyArgs struct{}

func (a VerifyArgs) Match(v driver.Value) bool {
    expectedName, strOk := v.(string)   
        expectedAge, int64Ok := v.(int64)
        expectedActived, boolOk := v.(bool)

    if strOk && expectedName == "hello" {
        return true
    } else if int64Ok && expectedAge == 18 {
        return true
    } else if boolOk && !expectedActived {
                return true
        }
    return false
}

For the test you could do something like this

sqlmock.ExpectExec(...).WithArgs(VerifyArgs{}, VerifyArgs{}, VerifyArgs{}).WillReturnResult(...)