【问题标题】:Mocking redis server with miniredis fails使用 miniredis 模拟 redis 服务器失败
【发布时间】:2020-06-29 00:31:07
【问题描述】:

Golang 新手在这里 :)
我在 go-redis 上有一个 redis 客户端包装器,我想测试它是否正常工作。我曾尝试使用 miniredis 来模拟我将要连接的 redis 服务器,但我一直收到错误消息。

当我将所有内容都放在同一个函数中时,它就可以工作了——我可以针对 miniredis 服务运行 go-redis。但是,当我尝试使用我的客户端时它失败了。
我试过查看 go-redis 和 miniredis 的文档,但找不到任何答案。我也尝试过将 miniredis 服务器定义为全局变量,但这也无济于事。

客户端实现:

package redis

import (
    "errors"
    "fmt"
    "github.com/go-redis/redis"
    "go.uber.org/zap"
    "os"
    "strconv"
    "time"
)

var redisClient *redis.Client
var redisCert string

var redisURL = "localhost:6379"
var redisPass = ""
var redisDB = 0

type Client struct {
    redisClient *redis.Client
}
func newRedisClient() *Client {
    if os.Getenv("REDIS_URL") != "" {
        redisURL = os.Getenv("REDIS_URL")
    }
    if os.Getenv("REDIS_PASS") != "" {
        redisPass = os.Getenv("REDIS_PASS")
    }
    if os.Getenv("REDIS_DB") != "" {
        redisDB, _ = strconv.Atoi(os.Getenv("REDIS_DB"))
    }

    client := redis.NewClient(&redis.Options{
        Addr:      redisURL,
        Password:  redisPass,
        DB:        redisDB,
    })
    redisClient = client
    _, err := redisClient.Ping().Result()
    if err != nil {
        fmt.Println("Failed to connect", zap.Error(err))
        return nil
    }
    fmt.Println("Redis client is ready")
    return &Client{redisClient: client}
}

func (r *Client) Get(key string) (string, error) {
    res, err := redisClient.Get(key).Result()
    fmt.Println(res, err)
    if err == redis.Nil {
        return "", errors.New("Key Not Found")
    } else if err != nil {
        return "", err
    } else {
        return res, nil
    }

}

测试实现:

package redis

import (
    "github.com/alicebob/miniredis/v2"
    "gopkg.in/go-playground/assert.v1"
    "os"
    "testing"
)

var mr *miniredis.Miniredis

func TestGet(t *testing.T) {
    mr, _ = miniredis.Run()
    mr.Set("test1", "some")
    os.Setenv("REDIS_URL", mr.Addr())
    c := newRedisClient()
    r, err := c.Get("test1")
    assert.Equal(t, r, "")
    assert.Equal(t, err, "")
    mr.Close()
}

我做错了什么?

【问题讨论】:

  • 你到底遇到了什么错误?
  • @minitauros 我收到 EOF 作为错误。确保连接的 ping 调用返回以下日志错误:Failed to connect {"service": "redis", "error": "EOF"}
  • 如果你将代码从TestGet 移动到newRedisClient 函数中,它可以工作吗?
  • 是的。如果 miniredis 在与调用它的函数相同的函数中启动,则它可以工作
  • 您是否调试并发现您连接的redisURL 的值是什么? newRedisClientmr.Addr()TestGet() 中返回的内容是否相同?

标签: go redis go-testing go-redis


【解决方案1】:

抱歉这么久才回复。我已经在本地运行了你的代码,我没有收到错误。

普通文件

package redis

import (
    "errors"
    "fmt"
    "os"
    "strconv"

    "github.com/go-redis/redis"
    "go.uber.org/zap"
)

var redisClient *redis.Client
var redisCert string

var redisURL = "localhost:6379"
var redisPass = ""
var redisDB = 0

type Client struct {
    redisClient *redis.Client
}

func newRedisClient() *Client {
    if os.Getenv("REDIS_URL") != "" {
        redisURL = os.Getenv("REDIS_URL")
    }
    if os.Getenv("REDIS_PASS") != "" {
        redisPass = os.Getenv("REDIS_PASS")
    }
    if os.Getenv("REDIS_DB") != "" {
        redisDB, _ = strconv.Atoi(os.Getenv("REDIS_DB"))
    }

    client := redis.NewClient(&redis.Options{
        Addr:     redisURL,
        Password: redisPass,
        DB:       redisDB,
    })
    redisClient = client
    _, err := redisClient.Ping().Result()
    if err != nil {
        fmt.Println("Failed to connect", zap.Error(err))
        return nil
    }
    fmt.Println("Redis client is ready")
    return &Client{redisClient: client}
}

func (r *Client) Get(key string) (string, error) {
    res, err := redisClient.Get(key).Result()
    if err == redis.Nil {
        return "", errors.New("Key Not Found")
    } else if err != nil {
        return "", err
    } else {
        return res, nil
    }

}

测试文件

package redis

import (
    "fmt"
    "os"
    "testing"

    "github.com/alicebob/miniredis/v2"
)

var mr *miniredis.Miniredis

func TestGet(t *testing.T) {
    var err error

    mr, err = miniredis.Run()
    fmt.Printf("Run err: %v\n", err)
    fmt.Printf("mr.Addr(): %v\n", mr.Addr())

    err = mr.Set("test1", "some")
    fmt.Printf("Set err: %v\n", err)

    err = os.Setenv("REDIS_URL", mr.Addr())
    fmt.Printf("Setenv err: %v\n", err)

    c := newRedisClient()
    r, err := c.Get("test1")

    fmt.Printf("Get err: %v\n", err)
    fmt.Printf("r: %v\n", r)

    mr.Close()
}

结果

go test
Run err: <nil>
mr.Addr(): 127.0.0.1:54966
Set err: <nil>
Setenv err: <nil>
Redis client is ready
Get err: <nil>
r: some
PASS
ok      test/sof        0.536s

【讨论】:

    【解决方案2】:

    通过miniredis模拟失败,可以使用SetError:https://github.com/alicebob/miniredis/issues/36#issuecomment-642009898

    func TestGet(t *testing.T) {
        mr, _ = miniredis.Run()
    
        // normal test
        // ...
    
        // error test
        mr.SetError("mock error")
        _, err = c.Get("test2")
        assert.EqualError(t, err, "mock error")
    
        mr.Close()
    }
    

    【讨论】:

      猜你喜欢
      • 2017-02-10
      • 1970-01-01
      • 2015-04-01
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      相关资源
      最近更新 更多