我正在尝试创建一个包装器,用于围绕 Go Flex SDK for Google Cloud Datastore 进行测试模拟。虽然我目前成功运行本地主机模拟器使用
gcloud beta emulators datastore start --no-store-on-disk
在与我的测试窗口不同的终端中,我更愿意创建一个作为测试过程本身的一部分运行的模拟数据库模拟器(没有上面的
exec
),以便我可以并行运行多个测试,每个测试都有自己的数据库模拟器.我遇到了 Google SDK 没有实现我的界面的问题。
我的包装器包含以下代码:
package google
import (
"context"
"cloud.google.com/go/datastore"
)
type (
// Datastore is a wrapper for the Google Cloud Datastore Client.
Datastore datastore.Client
// Datastorer represents things that can operate like a datastore.Client.
Datastorer interface {
Delete(context.Context, *datastore.Key) error
Get(context.Context, *datastore.Key, interface{}) error
GetAll(context.Context, *datastore.Query, interface{}) ([]*datastore.Key, error)
Put(context.Context, *datastore.Key, interface{}) (*datastore.Key, error)
PutMulti(context.Context, []*datastore.Key, interface{}) ([]*datastore.Key, error)
RunInTransaction(context.Context, func(Transactioner) error, ...datastore.TransactionOption) (*datastore.Commit, error)
}
// Transactioner represents things that can operate like a datastore.Transaction.
Transactioner interface {
Commit() (*datastore.Commit, error)
Delete(*datastore.Key) error
DeleteMulti([]*datastore.Key) error
Get(*datastore.Key, interface{}) error
GetMulti([]*datastore.Key, interface{}) error
Put(*datastore.Key, interface{}) (*datastore.PendingKey, error)
PutMulti([]*datastore.Key, interface{}) ([]*datastore.PendingKey, error)
Rollback() error
}
)
// Delete deletes the entity for the given key.
func (d *Datastore) Delete(ctx context.Context, key *datastore.Key) error {
return (*datastore.Client)(d).Delete(ctx, key)
}
// Get retrieves the entity for the given key.
func (d *Datastore) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
return (*datastore.Client)(d).Get(ctx, key, dst)
}
// GetAll retrieves all entities for the given query.
func (d *Datastore) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).GetAll(ctx, q, dst)
}
// Put stores an entity for the given key.
func (d *Datastore) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
return (*datastore.Client)(d).Put(ctx, key, src)
}
// PutMulti is a batch version of Put.
func (d *Datastore) PutMulti(ctx context.Context, keys []*datastore.Key, src interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).PutMulti(ctx, keys, src)
}
// RunInTransaction runs the given function in a transaction.
func (d *Datastore) RunInTransaction(ctx context.Context, f func(tx Transactioner) error, opts ...datastore.TransactionOption) (*datastore.Commit, error) {
return (*datastore.Client)(d).RunInTransaction(ctx, func(t *datastore.Transaction) error {
return f(t)
}, opts...)
}
请注意,这些接口(interface)不会模拟完整的 SDK。我只包括我在代码中实际调用的函数。稍后我会根据需要添加新的。
当我尝试使用
*datastore.Client
的实例作为 Datastorer
时,出现以下错误:cannot use client (type *"cloud.google.com/go/datastore".Client) as type Datastorer in field value:
*"cloud.google.com/go/datastore".Client does not implement Datastorer (wrong type for RunInTransaction method)
have RunInTransaction(context.Context, func(*"cloud.google.com/go/datastore".Transaction) error, ..."cloud.google.com/go/datastore".TransactionOption) (*"cloud.google.com/go/datastore".Commit, error)
want RunInTransaction(context.Context, func(Transactioner) error, ..."cloud.google.com/go/datastore".TransactionOption) (*"cloud.google.com/go/datastore".Commit, error)
因为
*datastore.Client
需要一个接受 func(*datastore.Transaction) error
的函数,而我的界面需要一个 func(Transactioner) error
。有什么办法可以改变它以便编译吗?
如果我可以让它工作,我计划创建实现我的
Datastorer
和 Transactioner
接口(interface)的类型,并使用映射来模拟真实的数据库。就事务处理而言,如果需要,我可以使用 sync.Mutex
进行测试,但由于每个测试都是一个线程并且将获得自己的数据库对象,因此我可能不需要锁定它们。 最佳答案
我已经使用以下代码编译它:
package google
import (
"context"
"cloud.google.com/go/datastore"
)
type (
// Datastore is a wrapper for the Google Cloud Datastore Client.
Datastore struct {
*datastore.Client
}
// Datastorer represents things that can operate like a datastore.Client.
Datastorer interface {
Delete(context.Context, *datastore.Key) error
Get(context.Context, *datastore.Key, interface{}) error
GetAll(context.Context, interface{}, interface{}) ([]*datastore.Key, error)
Put(context.Context, *datastore.Key, interface{}) (*datastore.Key, error)
PutMulti(context.Context, []*datastore.Key, interface{}) ([]*datastore.Key, error)
RunInTransaction(context.Context, func(Transactioner) error, ...datastore.TransactionOption) (*datastore.Commit, error)
}
// Querier represents things that can operate like a datastore.Query.
Querier interface {
Filter(string, interface{}) Querier
}
// Transactioner represents things that can operate like a datastore.Transaction.
Transactioner interface {
Commit() (*datastore.Commit, error)
Delete(*datastore.Key) error
DeleteMulti([]*datastore.Key) error
Get(*datastore.Key, interface{}) error
GetMulti([]*datastore.Key, interface{}) error
Put(*datastore.Key, interface{}) (*datastore.PendingKey, error)
PutMulti([]*datastore.Key, interface{}) ([]*datastore.PendingKey, error)
Rollback() error
}
)
// Delete deletes the entity for the given key.
func (d *Datastore) Delete(ctx context.Context, key *datastore.Key) error {
return d.Client.Delete(ctx, key)
}
// Get retrieves the entity for the given key.
func (d *Datastore) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
return d.Client.Get(ctx, key, dst)
}
// GetAll retrieves all entities for the given query.
func (d *Datastore) GetAll(ctx context.Context, q interface{}, dst interface{}) ([]*datastore.Key, error) {
return d.Client.GetAll(ctx, q.(*datastore.Query), dst)
}
// Put stores an entity for the given key.
func (d *Datastore) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
return d.Client.Put(ctx, key, src)
}
// PutMulti is a batch version of Put.
func (d *Datastore) PutMulti(ctx context.Context, keys []*datastore.Key, src interface{}) ([]*datastore.Key, error) {
return d.Client.PutMulti(ctx, keys, src)
}
// RunInTransaction runs the given function in a transaction.
func (d *Datastore) RunInTransaction(ctx context.Context, f func(tx Transactioner) error, opts ...datastore.TransactionOption) (*datastore.Commit, error) {
return d.Client.RunInTransaction(ctx, func(t *datastore.Transaction) error {
return f(t)
}, opts...)
}
我将
DataStore
更改为包含 struct
的 datastore.Client
并添加了一个新接口(interface) Querier
,其中包含我从 datastore.Query
使用的函数。我还更新了 GetAll
以接受 interface{}
而不是 *datastore.Query
,然后将其类型断言为 *datastore.Query
。我不能让它接受 Querier
因为这样我就不能传递 *datastore.Query
类型的变量,因为它们不满足 Querier
接口(interface)( Filter
返回一个 Querier
而不是 *datastore.Query
)。使用在单独进程中运行的模拟器的所有现有测试都通过。
更新 :
我将
Datastore
改为Datastore datastore.Client
并在
Query
周围添加了一个包装器 datastore.Query
:Query datastore.Query
现在,
Datastorer
接口(interface)包含GetAll(context.Context, Querier, interface{}) ([]*datastore.Key, error)
GetAll
函数定义为func (d *Datastore) GetAll(ctx context.Context, q Querier, dst interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).GetAll(ctx, (*datastore.Query)(q.(*Query)), dst)
}
Query.Filter
定义为func (q *Query) Filter(filterStr string, value interface{}) Querier {
return (*Query)((*datastore.Query)(q).Filter(filterStr, value))
}
在调用代码时,我使用
q := datastore.NewQuery(entity).Filter("Deleted =", false)
_, err := r.client.GetAll(ctx, (*Query)(q), data)
这将编译并且所有测试都通过。
关于go - 模拟 Go 数据库 SDK,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45941260/