DATA-DOG / go-sqlmock

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

Question: how to use with postgres text[] field? #201

Open shaunc opened 4 years ago

shaunc commented 4 years ago

My code uses pg.Array to read a text[] field. Can I use this package to test this code? ... if so, how?

Thanks!

l3pp4rd commented 4 years ago

Hi, it requires a ValueConverter registered through the sqlmock.Option. if the driver you use provides those ValueConverters, you should just register them. Otherwise you may need to copy them from the source code. As far as I've heard it works fine, is just the arrays are not the standard values in go standard database driver

guillermo-menjivar commented 4 years ago

@shaunc I add the same challenge to convert my array of strings into psql array. I used pq.Array from "github.com/lib/pq" against the value of a row I wanted sqlmock to return on a select statement. Hope this can be helpful

mintyknight commented 1 year ago

@shaunc, +1 to @guillermo-menjivar, I got inspired by his comment above, but I did slightly differently. Since I don't wish to introduce a whole new package into my project just for this. I wrote a function to convert my []string into something like following stringForQuery := "{\"firstString\",\"secondString\"}" Now both my Postgres and Sqlmock are working.

fgrosse commented 1 year ago

Using a ValueConverter did the trick just as @l3pp4rd suggested. This is the working code, assuming you are using pq.StringArray(…) in your code:

// StringArrayConverter is a database/sql driver.ValueConverter implementation
// that is used in our unit tests to teach sqlmock about the pq.StringArray type.
type StringArrayConverter struct{}

// ConvertValue converts a value to a driver Value.
func (s StringArrayConverter) ConvertValue(v any) (driver.Value, error) {
    switch x := v.(type) {
    case pq.StringArray:
        return []string(x), nil
    default:
        return x, nil
    }
}

func TestRepository(t *testing.T) {
    db, mock, err := sqlmock.New(sqlmock.ValueConverterOption(new(StringArrayConverter)))
    …
}
ns-tdemelocosta commented 1 year ago

@fgrosse Your suggestions doesn't seems to be working.

rows := sqlmock.NewRows([]string{"ns_tenant_id", "role_id", "rbac_version", "obfuscation_fields", "users_scope", "case_sensitive_groups", "groups_scope_exclude", "groups_scope", "app_instance_scope", "ou_scope", "scope_query", "insertion_timestamp"}).
                AddRow(1, 1, "v1", pq.StringArray{"field1", "field2"}, pq.StringArray{"user1", "user2"}, 0, 0, pq.StringArray{"group1", "group2"}, pq.StringArray{"app1", "app2"}, pq.StringArray{"ou1", "ou2"}, "query", "2023-08-07T00:00:00Z")

            query := fmt.Sprintf("SELECT (.+) FROM .table1 WHERE ns_tenant_id = %d", test.nsTenantID)
            mock.ExpectQuery(query).WillReturnRows(rows)

the error is *fmt.wrapError(&fmt.wrapError{msg:"sql: Scan error on column index 3, name \"obfuscation_fields\": unsupported Scan, storing driver.Value type string into type *[]string", err:(*errors.errorString)(0x14000298ec0)})

Is this the correct way to mock?