让我先说一下我是Go的新手,所以我在寻找其他图书馆时的模拟技巧。我很清楚接口和依赖注入是保持代码可测试和可模拟的最佳方法。
在使用第三方客户端库(Google云端存储)时,我遇到了尝试模拟其客户端实施的问题。主要问题是客户端库中的类型不是通过接口实现的。我可以生成模仿客户端实现的接口。但是,某些函数的返回值会返回指向底层结构类型的指针,这些结构类型由于私有属性而难以模拟或无法模拟。以下是我要解决的问题示例:
package third_party
type UnderlyingType struct {
secret string
}
type ThirdPartyClient struct {}
func (f *ThirdPartyClient) SomeFunction() *UnderlyingType {
return &UnderlyingType{
secret: "I can't mock this, it's a secret to the package"
}
}
这是一个带注释的示例,其中包含我试图解决的问题。
package mock
// Create interface that matches third party client structure
type MyClientInterface interface {
SomeFunction() *third_party.UnderlyingType
}
type MockClient struct {
third_party.Client
}
// Forced to return the third party non-interface type 'UnderlyingType'
func (f *MockClient) SomeFunction() *UnderlyingType {
// No way to mock the value of the 'secret' property outside
// of the third-party package. Any underlying methods that
// depend on a non-nil reference to 'secret' will explode
// with the mock.
//
// TODO: Find a way to mock the 'secret' value
return &UnderlyingType{}
}
这甚至是一个可以模仿的场景吗?有没有特殊的技术可以解决这个库没有提供任何接口作为返回类型的事实?
答案 0 :(得分:0)
您的问题的答案是:是的,这就是您可以做到的方式。
但是你问错了问题。您不应该询问如何嘲笑某些东西。因为,什么时候需要模拟?
仅用于测试。因此,您应该举一个具体的例子来测试您要测试的内容。
使用外部软件包时,有两种可能。您想测试外部程序包的行为是否符合您的预期,或者您信任该外部程序包,而您只是在测试代码。
因此,在测试代码时,需要测试客户端是否正确。因此,对于这种情况,您的模拟是可以的。请记住,重要的是要测试的内容,而不是是否可以嘲笑某些东西。
答案 1 :(得分:0)
通常,在处理非测试友好的第三方库时,您可以采取的一种方法是通过中间层将第三方代码抽象掉。
// mock and use this interface
type IntermediateLayer interface {
DoSomething()
}
type intermediateImplementation struct{}
func (i intermediateImplementation) DoSomething() {
client := &ThirdPartyClient{}
underlyingValue := client.SomeFunction()
underlyingValue.SomeOtherFunction()
}
您可以模拟IntermediateLayer
接口并测试使用该接口的业务代码。您将需要创建一个实现IntermediateLayer
接口并使用第三方API来实现您的目标的结构。
然后,问题将转移到测试IntermediateLayer
。根据使用第三方库的代码的复杂程度,您可以选择不对其进行测试,也可以将其交给更高级别的测试(例如集成测试)来进行验证。
走这条路的一个好处是,您可以将业务代码与第三方库解耦,这使您可以在将来的某个时候切换到其他第三方库,而不必重新编写所有代码。您甚至可以考虑使用这种方法,即使在与测试友好的第三方库打交道时,也要付出更多抽象和样板代码的代价。