Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server sqlmock中MSSQL表值参数的测试_Sql Server_Go_Go Sqlmock - Fatal编程技术网

Sql server sqlmock中MSSQL表值参数的测试

Sql server sqlmock中MSSQL表值参数的测试,sql-server,go,go-sqlmock,Sql Server,Go,Go Sqlmock,我有一个函数,该函数旨在使用表值参数和过程将大量元素插入MSSQL数据库 func (requester *Requester) doQuery(ctx context.Context, dtos interface{}) error { conn, err := requester.conn.Conn(ctx) if err != nil { return err } defer func() { if clErr := con

我有一个函数,该函数旨在使用表值参数和过程将大量元素插入MSSQL数据库

func (requester *Requester) doQuery(ctx context.Context, dtos interface{}) error {
    conn, err := requester.conn.Conn(ctx)
    if err != nil {
        return err
    }

    defer func() {
        if clErr := conn.Close(); clErr != nil {
            err = clErr
        }
    }()

    tx, err := conn.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelRepeatableRead, ReadOnly: false})
    if err != nil {
        return err
    }

    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p)
        } else if err != nil {
            tx.Rollback()
        } else {
            tx.Commit()
    }()

    param := sql.Named("TVP", mssql.TVP{
        TypeName: "MyTypeName",
        Value:    dtos,
    })

    return tx.ExecContext(ctx, "EXEC [dbo].[usp_InsertConsumption] @TVP", param)
}
我为这个函数编写的测试包括在下面(注意,它取决于银杏和gomega):

现在,这段代码是为MySQL上下文编写的,因为我已经将代码移植到MSSQL,所以我得到了一个特殊的错误:

sql: converting argument with name \"TVP\" type: unsupported type mssql.TVP, a struct

sqlmock似乎正在尝试调用TVP对象上的
ConvertValue
,这是无效的。那么,如何使sqlmock正确处理该值,以便能够围绕查询进行单元测试呢?

我在这里发现,sqlmock有一个名为
ValueConverterOption
的函数,当提供了一个自定义
驱动程序.ValueConverter
接口时。每次调用
ConvertValue
时,都会调用此函数来代替标准函数。如果您想在
ExecContext
函数接收到非标准参数(本例中为
TVP
)时测试该函数,则可以使用该函数将自定义转换逻辑注入sqlmock

type mockTvpConverter struct {}

func (converter *mockTvpConverter) ConvertValue(raw interface{}) (driver.Value, error) {

    // Since this function will take the place of every call of ConvertValue, we will inevitably
    // the fake string we return from this function so we need to check whether we've recieved
    // that or a TVP. More extensive logic may be required
    switch inner := raw.(type) {
    case string:
        return raw.(string), nil
    case mssql.TVP:

        // First, verify the type name
        Expect(inner.TypeName).Should(Equal("MyTypeName"))

        // VERIFICATION LOGIC HERE

        // Finally, return a fake value that we can use when verifying the arguments
        return "PASSED", nil
    }

    // We had an invalid type; return an error
    return nil, fmt.Errorf("Invalid type")
}
这意味着,测试将变成:

Describe("SQL Tests", func() {

    It("AddConsumption - No failures - Added", func() {

        db, mock, _ := sqlmock.New(sqlmock.ValueConverterOption(&mockTvpConverter{}))
        requester := Requester{conn: db}
        defer db.Close()

        mock.ExpectBegin()
        mock.ExpectExec(regexp.QuoteMeta("EXEC [dbo].[usp_InsertConsumption] @TVP")).
            WithArgs("PASSED").WillReturnResult(sqlmock.NewResult(1, 1))
        mock.ExpectExec(regexp.QuoteMeta("EXEC [dbo].[usp_InsertTags] @TVP")).
            WithArgs("PASSED").WillReturnResult(sqlmock.NewResult(1, 1))
        mock.ExpectCommit()

        err := requester.doQuery(context.TODO(), generateData())
        Expect(err).ShouldNot(HaveOccurred())
        Expect(mock.ExpectationsWereMet()).ShouldNot(HaveOccurred())
    })
})
Describe("SQL Tests", func() {

    It("AddConsumption - No failures - Added", func() {

        db, mock, _ := sqlmock.New(sqlmock.ValueConverterOption(&mockTvpConverter{}))
        requester := Requester{conn: db}
        defer db.Close()

        mock.ExpectBegin()
        mock.ExpectExec(regexp.QuoteMeta("EXEC [dbo].[usp_InsertConsumption] @TVP")).
            WithArgs("PASSED").WillReturnResult(sqlmock.NewResult(1, 1))
        mock.ExpectExec(regexp.QuoteMeta("EXEC [dbo].[usp_InsertTags] @TVP")).
            WithArgs("PASSED").WillReturnResult(sqlmock.NewResult(1, 1))
        mock.ExpectCommit()

        err := requester.doQuery(context.TODO(), generateData())
        Expect(err).ShouldNot(HaveOccurred())
        Expect(mock.ExpectationsWereMet()).ShouldNot(HaveOccurred())
    })
})