英文:
Mocking a type where interface signature's types are also mocked
问题
我正在尝试在不编辑现有库的情况下编写一个包装器,同时允许使用模拟进行测试。
为了进行测试和模拟,我创建了满足现有库类型签名的接口,并使用了mockgen。我还必须模拟这些接口类型签名中函数返回的一些类型。
然而,这样做会导致接口不再满足现有库的要求。
示例:
我有一个ClientType
,它有一个名为Subscribe
的函数,返回一个SubscriptionType
。
func NewClientType() ClientType {
return ClientType{"project name"}
}
type ClientType struct {
projectID string
}
func (l *ClientType) Subscribe(subID string) SubscriptionType {
return SubscriptionType{subID}
}
type SubscriptionType struct {
subscriptionID string
}
func (t *SubscriptionType) Receive() {
fmt.Println("Stuff")
}
我想模拟Receive
方法。
这将允许我创建一个Client,将其订阅到一个主题,然后在测试中模拟接收消息。
我尝试了以下代码:
type MyLibraryWrapper struct {
ClientType
}
type MockedClientType interface {
Subscribe(string) MockedSubscriptionType
}
type MockedSubscriptionType interface {
Receive()
}
func main() {
client := NewClientType()
myMockedType := NewWrapper(client)
sub := myMockedType.Subscribe("a")
_ = sub // 使用它
}
func NewWrapper(client ClientType) MyLibraryWrapper {
return MyLibraryWrapper{client}
}
这会产生以下错误:
cannot use client (type ClientType) as type MockedClientType in argument to NewWrapper:
ClientType does not implement MockedClientType (wrong type for Subscribe method)
have Subscribe(string) SubscriptionType
want Subscribe(string) MockedSubscriptionType
演示链接:
https://go.dev/play/p/6Pr_Y4VtOAW
英文:
I'm trying to write a wrapper around an existing library that I do not want to edit, while allowing testing via mocking.
To allow for testing and mocking, I have created interfaces that satisfy the type signatures of the existing library and am using mockgen. I must also mock some of the types returned by the functions in these interface type signatures.
However, doing this causes the interface to no longer satisfy the existing library.
Example:
I have a ClientType
, this has a function Subscribe
, which returns a SubscriptionType
.
func NewClientType() ClientType {
return ClientType{"project name"}
}
type ClientType struct {
projectID string
}
func (l *ClientType) Subscribe(subID string) SubscriptionType {
return SubscriptionType{subID}
}
type SubscriptionType struct {
subscriptionID string
}
func (t *SubscriptionType) Receive() {
fmt.Println("Stuff")
}
I want to mock the Receive
method.
This will allow me to create a Client, Subscribe it to a topic, and then mock this Receiving a message in testing.
I tried:
type MyLibraryWrapper struct {
ClientType
}
type MockedClientType interface {
Subscribe(string) MockedSubscriptionType
}
type MockedSubscriptionType interface {
Receive()
}
func main() {
client := NewClientType()
myMockedType := NewWrapper(client)
sub := myMockedType.Subscribe("a")
_ = sub // use it
}
func NewWrapper(client ClientType) MyLibraryWrapper {
return MyLibraryWrapper{client}
}
That gives:
<!-- language: lang-none -->
cannot use client (type ClientType) as type MockedClientType in argument to NewWrapper:
ClientType does not implement MockedClientType (wrong type for Subscribe method)
have Subscribe(string) SubscriptionType
want Subscribe(string) MockedSubscriptionType
Live demo:
答案1
得分: 1
你的库API是硬编码为返回struct
。在模拟任何东西之前,你必须先将每个struct
包装在一个接口中。
通过嵌入,这个任务变得更容易。
type MyLibraryWrapper struct {
ClientType
}
type MyClientType interface {
Subscribe(string) MySubscriptionType
}
type MySubscriptionType interface {
Receive()
}
func NewWrapper(client ClientType) MyClientType {
return MyLibraryWrapper{client}
}
现在你可以进行模拟了...
type MockLibraryWrapper struct {}
type MockSubscriptionType struct {}
func (MyMockLibraryWrapper) Subscribe(string) MySubscriptionType {
return MockSubscriptionType{}
}
func (MockSubscriptionType) Receive() {}
func NewMockClientType() MyClientType {
return MockLibraryWrapper{}
}
示例用法:
func main() {
realClient := NewWrapper(NewClientType())
sub := realClient.Subscribe("a")
sub.Receive()
mockClient := NewMockClientType()
sub := mockClient.Subscribe("a")
sub.Receive()
}
英文:
Your library API is hardcoded to return struct
s. You have to wrap each of its struct
in an interface first before you can mock anything.
With embedding that task becomes easier.
type MyLibraryWrapper struct {
ClientType
}
type MyClientType interface {
Subscribe(string) MySubscriptionType
}
type MySubscriptionType interface {
Receive()
}
func NewWrapper(client ClientType) MyClientType {
return MyLibraryWrapper{client}
}
Now you can mock it...
type MockLibraryWrapper struct {}
type MockSubscriptionType struct {}
func (MyMockLibraryWrapper) Subscribe(string) MySubscriptionType {
return MockSubscriptionType{}
}
func (MockSubscriptionType) Receive() {}
func NewMockClientType() MyClientType {
return MockLibraryWrapper{}
}
Example usage:
func main() {
realClient := NewWrapper(NewClientType())
sub := realClient.Subscribe("a")
sub.Receive()
mockClient := NewMockClientType()
sub := mockClient.Subscribe("a")
sub.Receive()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论