-
Notifications
You must be signed in to change notification settings - Fork 0
golang sqlmock extend
foolmacky edited this page Nov 18, 2022
·
2 revisions
何をしたいのか?
- mockに対して、期待するAction, 期待されるParam0がセットされる
- db.Execが実行され、Param1が与えられる
- 与えられたパラメータがチェックされるが無視される
- param1の内容がparam0に置き換えられる
ExpectExec{
queryBasedExpectation{
commonExpectation{
sync.Mutex
triggered bool
err error
}
}
expectSQL string
converter driver.ValueConverter
args []driver.Value
}
result driver.Result
delay time.Duration
}
db, mock, err := New()
mock.ExceptExec("").WithArgs(param0).WithOutArgs(param1)
db.ExecOut("", param0)
--param0の値がparam1に置換される
db.Exec("", param0)
param0 = param1
独自タイプの場合、driverにわたす前にエラーになってしまう
2020/07/25 01:24:51 error : sql: converting argument with name "out" type: unsupported type sqlmock.anyArgument, a struct
2020/07/25 01:11:43 error : sql: converting argument with name "out" type: unsupported type main.MockOut, a struct
expectは nil, execはsql.Outの場合
2020/07/25 02:01:52 error : ExecQuery 'insert into hoge', arguments do not match: argument 2 expected [<nil> - <nil>] does not match actual [sql.Out - {_Named_Fields_Required:{} Dest:<nil> In:false}]
expect , exec ともパラメータがsql.Outの場合
driverにはそのまま渡されるが、Match不能でエラーになる
2020/07/25 02:05:50 error : ExecQuery 'insert into hoge', arguments do not match: could not convert 2 argument sql.Out - {_Named_Fields_Required:{} Dest:10 In:false} to driver value: unsupported type sql.Out, a struct
expectをAnyArgにして、実際のexecをsql.Outで与えれば、マッチングはOKになる。
あとは内部でparamを強制的に書き換える
args := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: sqlmock.AnyArg()},
}
args0 := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: sql.Out{Dest: 10}},
}
このパターンはだめ
args := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: sql.Out{Dest: sqlmock.AnyArg()}},
}
args0 := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: sql.Out{Dest: 10}},
}
- expectのパラメータはsql.OutをAnyArgに置換
- argを複製してdriver
2020/07/25 02:49:39 error : ExecQuery 'insert into hoge', arguments do not match: matcher main.MockOut could not match 2 argument driver.NamedValue - {Name:out Ordinal:3 Value:{_Named_Fields_Required:{} Dest:10 In:false}}
args := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: MockOut{Out: sql.Out{Dest: 20}}},
// {Name: "out", Value: sql.Out{Dest: sqlmock.AnyArg()}},
}
args0 := []sql.NamedArg{
{Name: "name", Value: "foolmacky"},
{Name: "age", Value: 50},
{Name: "out", Value: sql.Out{Dest: 10}},
}
// @TODO should we assert either all args are named or ordinal?
for k, v := range args {
// custom argument matcher
matcher, ok := e.args[k].(Argument)
if ok {
if !matcher.Match(v.Value) {
return fmt.Errorf("matcher %T could not match %d argument %T - %+v", matcher, k, args[k], args[k])
}
continue
}
//macher : expectで入れた値
//v : 実際のexecで入ってくる値
- trueをリターンする
- Execで与えられたparameterをResultOutで与えられた値で置換する
vはexecで与えられた値
matcherはResultOutで与えられているparamをArgument(interface)型に変換したもの
それによってMatch関数がcallされる
どの値に変換すべきかは、予めmatcherは知っていることができる
変化させる値は、exec時に与えられるSql.OutのDest: *pointer の実体側
sql.OutのDestはpointerで格納されている
{Name: "out", Value: MockOut{Dest: 20, In: true, Pmatch: true}},