招摇过市的Golang生成的API处理程序的模拟



我真的需要一些帮助来测试我的API的行为,让我解释一下上下文:

这个API是在go中编写的,该go由swagger使用存储库模式生成。在创建新对象的情况下,我需要检查数据库中是否已经存在该名称,因此我调用存储库的函数以按名称在数据库中获取应用程序(见下文(

func (a *mongoApplicationRepository) GetApplicationByName(name string, ctx context.Context) (*models.Application, error) {
_, span := otel.Tracer("GetApplicationByName").Start(ctx, "GetApplicationByName")
defer span.End()
var application models.Application
err := a.mgConn.Collection("applications").
FindOne(context.TODO(), bson.M{"name": name}).Decode(&application)
if err != nil {
if err == mongo.ErrNoDocuments {
return &application, nil
}
return nil, err
}
return &application, nil
}

这个函数由您可以在下面看到的api处理程序调用

type ApplicationCreateHandler struct {
API       *operations.KubeesAPI
repo      repo.ApplicationRepository
statsRepo repo.StatsRepository
}
func NewApplicationCreateHandler(API *operations.KubeesAPI, repo repo.ApplicationRepository, statsRepo repo.StatsRepository) ApplicationCreateHandler {
return ApplicationCreateHandler{
API:       API,
repo:      repo,
statsRepo: statsRepo,
}
}
// Handle is the HTTP handler for application creation
func (h *ApplicationCreateHandler) Handle(params application.AppCreateParams, principal *models.Principal) middleware.Responder {
traceName := "application-create"
ctx, span := otel.GetTracerProvider().Tracer(traceName).Start(context.TODO(), traceName)
defer span.End()
if params.Data == nil {
err := "unable to validate input"
logger().Errorln(err)
return application.NewAppCreateBadRequest().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if err := params.Data.Validate(h.API.Formats()); err != nil {
err := fmt.Sprintf("unable to validate input: %v", err)
logger().Errorln(err)
return application.NewAppCreateBadRequest().WithPayload(&models.APIResponse{
Msg: &err,
})
}
app := models.Application{
ID:       uuid.NewString(),
Name:     params.Data.Name,
Selector: params.Data.Selector,
}
c, err := h.repo.GetApplicationByName(*params.Data.Name, ctx)
if err != nil {
err := fmt.Sprintf("Unable to get Application: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if c.ID != "" {
r := "name already taken"
logger().Errorln(r)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &r,
})
}
appDomain, err := app.ToDomainModel()
if err != nil {
err := fmt.Sprintf("Unable to convert application to domain model: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
err = h.repo.CreateApplication(appDomain, ctx)
if err != nil {
err := fmt.Sprintf("Unable to create Application: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
if err := h.statsRepo.UpdateApplicationsHistory(ctx); err != nil {
err := fmt.Sprintf("unable to update applications history: %v", err)
logger().Errorln(err)
return application.NewAppCreateInternalServerError().WithPayload(&models.APIResponse{
Msg: &err,
})
}
return application.NewAppCreateCreated()
}

我只想检查这种行为并进行测试,以防我们已经有一个与新创建的应用程序调用相同的应用程序,这会引发错误,而不是相反的情况。但我不知道该模拟什么,因为存储库有一些外部依赖

我强烈建议确保您的ApplicationCreateHandler只依赖于接口。在这种情况下,您可以通过编写模拟类或在上生成来模拟接口。您可以测试ApplicationCreateHandlerby creating a new instance, and passing the mocked dependencies to it. Then execute theHandle((方法,并确保调用所有依赖项。

我强烈建议您生成模拟类。当您自己编写mock时,可能会在测试代码中引入错误。你不会想要的,对吧?

mockgen是一个很好的mocking库示例。您可以按照他们的github自述文件轻松安装它。

步骤

  1. 为依赖项创建接口
    最好在依赖接口的一侧定义接口。因此,在您的情况下,它将在ApplicationCreateHandler文件中。接口应该反映处理程序的需要
type (
ApplicationRepo interface {
GetApplicationByName(name string, ctx context.Context)
CreateApplication(domain Domain, ctx context.Context)
}
// other dependencies here... 
)
  1. 编写单元测试
    创建新的单元测试
// youfile_test.go
func TestApplicationHandler(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockRepo := NewMockRepository(ctrl)
mockRepo.EXPECT().
Handle(gomock.any(), gomock.any()). // name, ctx
Return(nil, nil).  // c, err
Once()
// other mocks...
// mockApi
// mockStatsRepo
h := NewApplicationHandler(mockApi, mockStats, mockRepo)
h.Handle(/*your test input*/)
// do checks
}

如果mockRepo没有被准确调用一次,测试将抛出一个错误。

最新更新