猿问

模拟 go 方法

我正在写一个小的 POC 去上班,但我似乎无法弄清楚模拟技术。这是我到目前为止...


连接.go


package db


import (

    "database/sql"

    "encoding/json"

    "fmt"

    "io/ioutil"

    "strings"


    _ "github.com/lib/pq"

)


type config map[string]interface{}


type DbConn struct {

    db db

}


type db interface {

    getConnectionStringFromConfig(file string) (connStr string, err error)

}


func NewDbConn(d db) *DbConn {

    return &DbConn{db: d}

}


func getConnectionStringFromConfig(file string) (connStr string, err error) {

    var c config

    var bt []byte

    if bt, err = ioutil.ReadFile(file); err != nil {

        fmt.Printf("Error Reading config file: %v", err)

        return

    }

    fmt.Println("Finish reading file. Going to construct a connection string")

    if err = json.Unmarshal(bt, &c); err != nil {

        fmt.Printf("Error unmarshalling config file: %v", err)

        return

    }

    connStr = strings.TrimLeft(getConfigAsString(c), " ")

    return

}


func getConfigAsString(c config) (connStr string) {

    for k, v := range c {

        connStr += strings.Join([]string{" " + k, v.(string)}, "=")

    }

    return

}


// Connect database connection

func (dbConn DbConn) Connect() (conn *sql.DB, err error) {

    fmt.Println("Starting database connection...")

    connStr, err := getConnectionStringFromConfig("path/to/conf.json")

    if err != nil {

        return

    }

    conn, err = sql.Open("some_driver", connStr)

    return

}

连接测试.go


package db


import (

    "errors"

    "testing"

)


type dbConnMock struct {

    db dbMock

}


type dbMock interface {

    getConnectionStringFromConfig(file string) (connStr string, err error)

}


func (dbm dbConnMock) getConnectionStringFromConfig(file string) (connStr string, err error) {

    return "", errors.New("123")

}


// should not throw error when trying to open db connection

func TestDatabaseConnection(t *testing.T) {

    dbCon := &DbConn{}

    _, err := dbCon.Connect()

    if err != nil {

        t.Errorf("test failed. \n %d", err)

    }

}

如您所见,这是一个简单的数据库连接逻辑,我使用接口对其进行了测试和模拟。我想覆盖 100% 的代码,所以我必须模拟某些方法。上面的代码虽然有效,但第二个测试失败了,可能是因为我在尝试模拟它时遗漏了一些东西。请帮忙..


30秒到达战场
浏览 116回答 1
1回答

喵喔喔

您可以做几件事。简单的方法如果你想保持简单,你可以做的是让你的模拟结构具有它应该返回的字段,并且在每个测试用例中你将这些字段设置为你的模拟应该为该测试用例返回的内容。这样,您可以以不同的方式使模拟成功或失败。此外,您不需要dbMock接口,因为dbConnMock实现了db接口,这就是您所需要的。这是您的模拟的样子:type dbConnMock struct {    FileCalled string    connStr string    err error}func (dbm dbConnMock) getConnectionStringFromConfig(file string) (connStr string, err error) {    dbm.FileCalled = file    return dbm.connStr, dbm.err}现在,您可以通过使用验证您的方法是否使用预期参数调用FileCalled,并且可以使其具有您想要模拟的行为。如果你还想确保你的方法只被调用一次,你还可以添加一个计数器来查看它被调用了多少次。使用模拟库如果您不想担心编写该逻辑,一些库可以为您完成,例如testify/mock。这是一个简单的模拟如何使用的示例testify/mock:type dbMock struct {    mock.Mock}func (m *dbMock) getConnectionStringFromConfig(file string) (string, error) {    args := m.Called(file)    return args.String(0), args.Error(1)}func TestSomething(t *testing.T) {    tests := []struct {        description string        connStr string        err error        expectedFileName string        // add expected outputs and inputs of your tested function    }{        {            description: "passing test",            connStr: "valid connection string",            err: nil,            expectedFileName: "valid.json",        },        {            description: "invalid file",            connStr: "",            err: errors.New("invalid file"),            expectedFileName: "invalid.json",        },    }    for _, test := range tests {        t.Run(test.description, func(t *testing.T) {            dbMock := &dbConnectionMock{}            dbMock.                On("getConnectionStringFromConfig", test.expectedFileName).                Return(test.connStr, test.err).                Once()            thing := &Something{                db: dbMock,            }            output, err := thing.doSomething()            // assert that output and err are expected            dbMock.AssertExpectations(t) // this will make sure that your mock is only used as expected in your test, depending on your `On` calls        })    }}此代码确保您的方法被调用一次并使用特定参数,并将使其返回测试用例中指定的内容。
随时随地看视频慕课网APP

相关分类

Go
我要回答