英文:
How to properly unit test mongoDB CRUD result
问题
我的应用程序主要使用mongo-go-drive
包对MongoDB进行CRUD操作。这个函数是gRPC服务器服务之一,它只是调用数据库方法action.GetProducts(ctx)
并返回*mongo.cursor
。然后对结果进行解码。对于每个文档,我将文档内容放入一个单独的产品结构体中,然后将其附加到产品切片中(使用gRPC proto的repeated GetProductResponse
类型创建了GetProductsResponse
结构体)。在将所有产品附加到GetProductsResponse
之后,将响应返回给gRPC客户端。
我对测试也不太熟悉,应该如何拆分函数并进行模拟(如何模拟游标)进行单元测试?首先,是否有必要对该函数进行单元测试,即使它只是将结果附加到切片中,或者是否应该直接进行集成测试并跳过单元测试,因为它涉及数据库I/O?
func (s *Server) GetProducts(ctx context.Context, in *pb.EmptyRequest) (*pb.GetProductsResponse, error) {
cursor, err := action.GetProducts(ctx)
if err != nil {
return nil, err
}
products := pb.GetProductsResponse{}
res := model.Product{}
for cursor.Next(ctx) {
// Convert document to above struct
err := cursor.Decode(&res)
if err != nil {
return nil, fmt.Errorf("failed to decode document: %v", err)
}
product := &pb.GetProductResponse{ProductId: res.Product_id.Hex(), Name: res.Name, Price: res.Price, Qty: int32(res.Qty)}
products.Products = append(products.Products, product)
}
return &products, nil
}
英文:
My application mostly consists of CRUDs to/from MongoDB using mongo-go-drive
package. This function is one of gRPC server services and all it does is calling database method action.GetProducts(ctx)
and it returns *mongo.cursor
. Then the result is decoded. For each document, I put the document content into a singular product struct, then append it to products slices (the GetProductsResponse
struct is made using gRPC proto repeated GetProductResponse
type). After appending all product into GetProductsResponse
, I return the response to gRPC client.
I am also new to testing in general, how should I break down the function and do the mocking (how to mock the cursor?) for unit testing? Is it even necessary in the first place to do unit test on the function even though all it does is appending the result, or should I just go straight for the integration test and skip the unit test since it involves database I/O?
func (s *Server) GetProducts(ctx context.Context, in *pb.EmptyRequest) (*pb.GetProductsResponse, error) {
cursor, err := action.GetProducts(ctx)
if err != nil {
return nil, err
}
products := pb.GetProductsResponse{}
res := model.Product{}
for cursor.Next(ctx) {
// Convert document to above struct
err := cursor.Decode(&res)
if err != nil {
return nil, fmt.Errorf("failed to decode document: %v", err)
}
product := &pb.GetProductResponse{ProductId: res.Product_id.Hex(), Name: res.Name, Price: res.Price, Qty: int32(res.Qty)}
products.Products = append(products.Products, product)
}
return &products, nil
}
答案1
得分: 1
如果您与数据库进行交互,那就不再是单元测试了,因为您正在与另一个外部系统进行集成。
无论如何,我通常会这样定义我的“repository”层函数:
package repo
var FetchUserById = func(id string) (*model.User, error){
// 这里是真正的逻辑
return user, err
}
然后,当我需要测试我的“service”层逻辑时,我会这样模拟整个“repository”层:
repo.FetchUserById = func(id string) (*model.User, err) {
return myMockedUser, nil
}
英文:
If you interact with the DB is not unit testing anymore, because you're integrating with another external system.
Anyway, I use to define my "repository" layer function this way:
package repo
var FetchUserById = func(id string) (*model.User, error){
// here the real logic
return user, err
}
and then, when I have to test my "service" layer logic, I would mock the entire "repository" layer this way:
repo.FetchUserById = func(id string) (*model.User, err) {
return myMockedUser, nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论