为了账号安全,请及时绑定邮箱和手机立即绑定

如何在同一结构中的另一个方法中调用存根方法

如何在同一结构中的另一个方法中调用存根方法

Go
一只斗牛犬 2022-06-06 15:53:14
代码在这里:package mainimport (  "fmt")type Connector struct {}func (c *Connector) Pool() (interface{}, error) {  err := c.ping()  if err != nil {    fmt.Println("error handle logic");    return nil, err  }  fmt.Println("success logic")  return 1, nil}func (c *Connector) ping() error {  var err error  // err = some side-effect RPC operation  if err != nil {    return err  }  return nil}现在,我想测试一下struct的Pool方法。Connector由于该ping方法有一些副作用 RPC 操作,我需要对它及其返回值进行存根,以便我可以测试该Pool方法中的每个代码分支。成功测试用例伪代码:Stub(c, "ping").Return(nil)c.Pool()Expect(fmt.Println).ToBeCalledWith("success logic")失败测试用例伪代码:Stub(c, "ping").Return(errors.New("test"))c.Pool()Expect(fmt.Println).ToBeCalledWith("error handle logic")
查看完整描述

1 回答

?
慕桂英546537

TA贡献1848条经验 获得超10个赞

我们需要遵循依赖倒置原则,这将使代码更容易测试。


细节(具体实现)应该依赖于抽象。


重构代码:


connector.go:


package connector


import (

    "fmt"

)


type Pinger interface {

    Ping() error

}


type Connector struct {

    DB Pinger

}


func (c *Connector) Pool() (interface{}, error) {

    err := c.DB.Ping()

    if err != nil {

        fmt.Println("error handle logic")

        return nil, err

    }

    fmt.Println("success logic")

    return 1, nil

}

现在,使用stretchr/testify包创建实现Pinger接口的模拟数据库。然后,将这个模拟的 DB 传递给struct,这是某种依赖注入。Connector


然后我们可以“模拟”Ping具有不同返回值的方法。


connector_test.go:


package connector_test


import (

    "fmt"

    "testing"


    connector "github.com/mrdulin/golang/src/stackoverflow/62035606"

    "github.com/stretchr/testify/mock"

    "github.com/stretchr/testify/require"

)


type MockedDB struct {

    mock.Mock

}


func (db *MockedDB) Ping() error {

    args := db.Called()

    return args.Error(0)

}


func TestConnector_Pool(t *testing.T) {

    t.Run("should verifies connection to the database is still alive", func(t *testing.T) {

        testDB := new(MockedDB)

        c := connector.Connector{DB: testDB}

        testDB.On("Ping").Return(nil)

        pool, err := c.Pool()

        require.Nil(t, err, nil)

        require.Equal(t, 1, pool)

    })


    t.Run("should return error if connection to the database is not alive", func(t *testing.T) {

        testDB := new(MockedDB)

        c := connector.Connector{DB: testDB}

        testDB.On("Ping").Return(fmt.Errorf("network"))

        pool, err := c.Pool()

        require.Error(t, err, "network")

        require.Nil(t, pool)

    })

}

单元测试结果:


=== RUN   TestConnector_Pool

=== RUN   TestConnector_Pool/should_verifies_connection_to_the_database_is_still_alive

success logic

=== RUN   TestConnector_Pool/should_return_error_if_connection_to_the_database_is_not_alive

error handle logic

--- PASS: TestConnector_Pool (0.00s)

    --- PASS: TestConnector_Pool/should_verifies_connection_to_the_database_is_still_alive (0.00s)

    --- PASS: TestConnector_Pool/should_return_error_if_connection_to_the_database_is_not_alive (0.00s)

PASS

coverage: 100.0% of statements

ok      github.com/mrdulin/golang/src/stackoverflow/62035606    0.364s

覆盖报告:

//img1.sycdn.imooc.com//629db2880001636416720987.jpg

查看完整回答
反对 回复 2022-06-06
  • 1 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信