亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

從包函數返回 Mock

從包函數返回 Mock

Go
拉丁的傳說 2023-07-26 15:32:31
我對 Go 相當陌生,在編寫測試時遇到了一些問題,特別是模擬包函數的響應。我正在為 編寫一個包裝器庫github.com/go-redis/redis。目前它確實只有更好的失敗錯誤,但它會隨著 statsd 進一步跟蹤而擴展,但我離題了......我創建了以下 go 包package myredisimport (    "time"    "github.com/go-redis/redis"    errors "github.com/pkg/errors")var newRedisClient = redis.NewClient// Options - My Redis Connection Optionstype Options struct {    *redis.Options    DefaultLifetime time.Duration}// MyRedis - My Redis Typetype MyRedis struct {    options Options    client  *redis.Client}// Connect - Connects to the Redis Server. Returns an error on failurefunc (r *MyRedis) Connect() error {    r.client = newRedisClient(&redis.Options{        Addr:     r.options.Addr,        Password: r.options.Password,        DB:       r.options.DB,    })    _, err := r.client.Ping().Result()    if err != nil {        return errors.Wrap(err, "myredis")    }    return nil}我的問題是我想redis.NewClient返回一個模擬。這是我寫的測試代碼,但它不起作用:package myredisimport (    "testing"    "github.com/go-redis/redis"    "github.com/stretchr/testify/assert"    "github.com/stretchr/testify/mock")type redisStatusCmdMock struct {    mock.Mock}func (m *redisStatusCmdMock) Result() (string, error) {    args := m.Called()    return args.Get(0).(string), args.Error(1)}type redisClientMock struct {    mock.Mock}func (m *redisClientMock) Ping() redis.StatusCmd {    args := m.Called()    return args.Get(0).(redis.StatusCmd)}func TestConnect(t *testing.T) {    assert := assert.New(t)    old := newRedisClient    defer func() { newRedisClient = old }()    newRedisClient = func(options *redis.Options) *redis.Client {        assert.Equal("127.0.0.1:1001", options.Addr)        assert.Equal("password", options.Password)        assert.Equal(1, options.DB)    }}我收到以下錯誤:cannot use clientMock (type *redisClientMock) as type *redis.Client in return argument。我想我讀到我需要模擬 的所有功能,redis.Client以便能夠在這種情況下將其用作模擬,但事實真的是這樣嗎?這似乎太過分了,我應該能夠以某種方式做到這一點。我該如何讓這個測試工作,或者我是否需要重組我的代碼以便更容易編寫測試?
查看完整描述

1 回答

?
千巷貓影

TA貢獻1829條經驗 獲得超7個贊

redis.Client是一種結構類型,并且在 Go 中結構類型根本不可模擬。然而 Go 中的接口是可模擬的,所以你可以做的是定義你自己的“newredisclient”函數,而不是返回一個結構,而是返回一個接口。由于 Go 中的接口是隱式滿足的,因此您可以定義接口,以便它可以由 redis.Client 開箱即用地實現。


type RedisClient interface {

    Ping() redis.StatusCmd

    // include any other methods that you need to use from redis

}


func NewRedisCliennt(options *redis.Options) RedisClient {

    return redis.NewClient(options)

}


var newRedisClient = NewRedisClient

如果您還想模擬 的返回值Ping(),則需要做更多的工作。


// First define an interface that will replace the concrete redis.StatusCmd.

type RedisStatusCmd interface {

    Result() (string, error)

    // include any other methods that you need to use from redis.StatusCmd

}


// Have the client interface return the new RedisStatusCmd interface

// instead of the concrete redis.StatusCmd type.

type RedisClient interface {

    Ping() RedisStatusCmd

    // include any other methods that you need to use from redis.Client

}

現在*redis.Client不再滿足接口RedisClient,因為 的返回類型Ping()不同。redis.Client.Ping()請注意, 的結果類型是否滿足 的返回接口類型并不重要RedisClient.Ping(),重要的是方法簽名不同,因此它們的類型不同。


要解決此問題,您可以定義一個*redis.Client直接使用并滿足新RedisClient接口的瘦包裝器。


type redisclient struct {

    rc *redis.Client

}


func (c *redisclient) Ping() RedisStatusCmd {

    return c.rc.Ping()

}


func NewRedisCliennt(options *redis.Options) RedisClient {

    // here wrap the *redis.Client into *redisclient

    return &redisclient{redis.NewClient(options)}

}


var newRedisClient = NewRedisClient


查看完整回答
反對 回復 2023-07-26
  • 1 回答
  • 0 關注
  • 113 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號