我是 Golang 的新手,在学习这门语言时一直采用 TDD 方法。我一直相处得很好,但我发现测试第三方软件包非常笨拙,这让我相信我一直在采取错误的方法。
我遇到问题的具体情况是模拟Redis 客户端以进行错误处理。我采用的方法是创建我自己的接口,并且实现包装了我想要使用的客户端方法。
type Redis interface {
Get(key string) (string, error)
}
type RedisClient struct {
client *redis.Client
}
func (redisClient *RedisClient) New(client *redis.Client) *RedisClient {
redisClient.client = client
return redisClient
}
func (redisClient *RedisClient) Get(key string) (string, error) {
return redisClient.client.Get(key).Result()
}
Run Code Online (Sandbox Code Playgroud)
然后我可以创建一个实现相同接口的模拟来返回我指定的任何值,特别是用于测试错误处理。
我遇到了一个障碍,即客户端执行交易的特定方法(MULTI) 返回属于该包的另一个接口。在这种情况下我会怎么做?自己实现该接口似乎是不可能的。
类似地,随着这个客户端使用量的增长,我自己的实现可以增长到它实现整个 Redis 接口的程度——这似乎与将其委托给外部依赖的整个想法背道而驰。
有没有更好的方法来测试这样的第三方包,比如错误处理?
一种方法是创建一个类型,专注于您想要完成的工作,而不是您正在使用的客户端的哪些方法。
假设您想要的只是一个用于保存和获取用户的存储空间,您可以想象这样的界面:
type UserStore interface {
SaveUser(*User) error
GetUserByID(id string) (*User, error)
SearchUsers(query string) ([]User, error)
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以实现此存储的 Redis 版本并在内部调用您想要的任何客户端方法,这无关紧要。你甚至可以在 PostgreSQL 或其他任何东西中实现一个。此外,使用这种方法模拟更容易,因为您需要做的就是实现这个接口而不是 Redis 接口。
以下是此接口的模拟版本示例:
type UserStoreMock struct {
SaveUserFn func (*User) error
SaveUserInvoked bool
...
}
func (m *UserStoreMock) SaveUser(u *User) error {
m.SaveUserInvoked = true
if m.SaveUserFn != nil {
return m.SaveUserFn(u)
}
return nil
}
...
Run Code Online (Sandbox Code Playgroud)
然后你可以在这样的测试中使用这个模拟:
var m UserStoreMock
m.SaveUserFn = func(u *User) error {
if u.ID != "123" {
t.Fail("Bad ID")
}
return ErrDuplicateError
}
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3097 次 |
| 最近记录: |