go - 如何提高 go 库方法的可测试性
问题描述
我正在编写一些使用名为Vault的库的代码。在这个库中,我们有一个Client
. 我的代码利用了这一点Client
,但我希望能够轻松测试使用它的代码。我只使用了库中的几个方法,所以我最终创建了一个接口:
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
现在,如果我的代码指向这一点,那么interface
一切都很容易测试。除了让我们看看Logical()
方法。它返回一个struct
here。我的问题是,这个Logical
结构上还有一些方法可以让你Read
,,,Write
例如:
func (c *Logical) Read(path string) (*Secret, error) {
return c.ReadWithData(path, nil)
}
这些也被用于我的项目中,以执行以下操作:
{{ VaultClient defined above }}.Logical().Write("something", something)
这是问题所在。Logical
从调用返回的方法.Logical()
有一个我无法模拟.Write
的方法。.Read
我不希望这些方法中的所有逻辑都在我的测试中运行。
理想情况下,我希望能够做类似于我上面所做的事情并创建一个interface
for Logical
。我对 Golang 比较陌生,但我正在努力寻找最好的方法。据我所知,这是不可能的。嵌入不像继承那样工作,所以看起来我必须返回一个Logical
. 这使得我的代码无法像我想要的那样简单地测试,因为 aLogical
的方法中的所有逻辑都不能被模拟。
我在这里有点不知所措。我已经在谷歌上搜索了这个问题的答案,但没有人谈论过这种情况。他们只走我interface
为客户最初的目标。
这是一个常见的场景吗?我用过的其他库不返回struct
s like Logical
。相反,它们通常只返回一个struct
包含数据且没有方法的平淡无奇的内容。
解决方案
package usecasevaultclient
// usecase.go
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
type vaultClient struct {
repo RepoVaultClient
}
// create new injection
func NewVaultClient(repo RepoVaultClient) VaultClient {
return &vaultClient{repo}
}
func(u *vaultClient) Logical() *api.Logical {
// do your logic and call the repo of
u.repo.ReadData()
u.repo.WriteData()
}
func(u *vaultClient) SetToken(v string) {}
func(u *vaultClient) NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
// interfaces.go
type RepoVaultClient interface {
ReadData() error
WriteData() error
}
// repo_vaultclient_mock.go
import "github.com/stretchr/testify/mock"
type MockRepoVaultClient struct {
mock.Mock
}
func (m *MockRepoVaultClient) ReadData() error {
args := m.Called()
return args.Error(0)
}
func (m *MockRepoVaultClient) WriteData() error {
args := m.Called()
return args.Error(0)
}
// vaultClient_test.go
func TestLogicalShouldBeSuccess(t *testing.T) {
mockRepoVaultClient = &MockRepoVaultClient{}
useCase := NewVaultClient(mockRepoVaultClient)
mockRepoVaultClient.On("ReadData").Return(nil)
mockRepoVaultClient.On("WriteData").Return(nil)
// your logics gonna make this response as actual what u implemented
response := useCase.Logical()
assert.Equal(t, expected, response)
}
如果要测试 Logical 的接口,则需要使用 testify/mock 模拟 ReadData 和 WriteData ,以便您可以定义这些方法的返回响应,并且可以在调用接口的新注入后进行比较
推荐阅读
- azure - 如何使用 Azure Cosmosdb SDK 创建无服务器 cosmosdb?
- python - 用理解创建的字典的深层副本不起作用
- python-3.x - 使用位置和关键字参数的顺序
- jquery - 如何从其他表中获取值并在数据表中显示
- redux - React-Redux useSelector 无法传递数据
- python - 在 Python 中的类之外定义类方法
- java - Java Web Start 拒绝自签名证书
- javascript - 'self' 脚本被阻止加载,但是当我使用 nonce 时它们可以工作吗?
- python - Python 长度不匹配
- javascript - 使用 JavaScript 制作添加到收藏夹按钮