1
0

feat: 系统性改进后端测试体系

- 新增 6 个测试场景 (config load pipe, handler errors, service aggregation, engine degradation, openai decoder edges, negative tests)
- 更新测试工具规格 (mockgen, in-memory SQLite)
- 覆盖率目标从 >80% 提升至 >85%
- 新增 test-unit 和 test-integration Makefile 命令
- 新增死代码清理和 mockgen 需求
- 归档变更至 openspec/changes/archive/2026-04-22-improve-backend-testing/
This commit is contained in:
2026-04-22 13:18:51 +08:00
parent 59179094ed
commit 4e86adffb7
32 changed files with 3374 additions and 729 deletions

View File

@@ -9,12 +9,19 @@ import (
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"nex/backend/internal/domain"
"nex/backend/tests/mocks"
)
func TestProviderHandler_CreateProvider_Success(t *testing.T) {
h := NewProviderHandler(&mockProviderService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockProviderService(ctrl)
mockSvc.EXPECT().Create(gomock.Any()).Return(nil)
h := NewProviderHandler(mockSvc)
body, _ := json.Marshal(map[string]string{
"id": "p1",
@@ -37,7 +44,12 @@ func TestProviderHandler_CreateProvider_Success(t *testing.T) {
}
func TestProviderHandler_CreateProvider_WithProtocol(t *testing.T) {
h := NewProviderHandler(&mockProviderService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockProviderService(ctrl)
mockSvc.EXPECT().Create(gomock.Any()).Return(nil)
h := NewProviderHandler(mockSvc)
body, _ := json.Marshal(map[string]string{
"id": "p1",
@@ -56,9 +68,13 @@ func TestProviderHandler_CreateProvider_WithProtocol(t *testing.T) {
}
func TestProviderHandler_UpdateProvider(t *testing.T) {
h := NewProviderHandler(&mockProviderService{
provider: &domain.Provider{ID: "p1", Name: "Updated", APIKey: "***"},
})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockProviderService(ctrl)
mockSvc.EXPECT().Update(gomock.Eq("p1"), gomock.Any()).Return(nil)
mockSvc.EXPECT().Get(gomock.Eq("p1"), gomock.Eq(true)).Return(&domain.Provider{ID: "p1", Name: "Updated", APIKey: "***"}, nil)
h := NewProviderHandler(mockSvc)
body, _ := json.Marshal(map[string]string{"name": "Updated"})
w := httptest.NewRecorder()
@@ -72,7 +88,11 @@ func TestProviderHandler_UpdateProvider(t *testing.T) {
}
func TestProviderHandler_UpdateProvider_InvalidBody(t *testing.T) {
h := NewProviderHandler(&mockProviderService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockProviderService(ctrl)
h := NewProviderHandler(mockSvc)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
@@ -84,7 +104,12 @@ func TestProviderHandler_UpdateProvider_InvalidBody(t *testing.T) {
}
func TestProviderHandler_DeleteProvider(t *testing.T) {
h := NewProviderHandler(&mockProviderService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockProviderService(ctrl)
mockSvc.EXPECT().Delete(gomock.Eq("p1")).Return(nil)
h := NewProviderHandler(mockSvc)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
@@ -97,7 +122,12 @@ func TestProviderHandler_DeleteProvider(t *testing.T) {
}
func TestModelHandler_DeleteModel(t *testing.T) {
h := NewModelHandler(&mockModelService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockModelService(ctrl)
mockSvc.EXPECT().Delete(gomock.Eq("m1")).Return(nil)
h := NewModelHandler(mockSvc)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
@@ -110,7 +140,15 @@ func TestModelHandler_DeleteModel(t *testing.T) {
}
func TestModelHandler_CreateModel_Success(t *testing.T) {
h := NewModelHandler(&mockModelService{})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockModelService(ctrl)
mockSvc.EXPECT().Create(gomock.Any()).DoAndReturn(func(model *domain.Model) error {
model.ID = "mock-uuid-1234"
return nil
})
h := NewModelHandler(mockSvc)
body, _ := json.Marshal(map[string]string{
"provider_id": "p1",
@@ -130,9 +168,12 @@ func TestModelHandler_CreateModel_Success(t *testing.T) {
}
func TestModelHandler_GetModel(t *testing.T) {
h := NewModelHandler(&mockModelService{
model: &domain.Model{ID: "m1", ModelName: "gpt-4"},
})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockModelService(ctrl)
mockSvc.EXPECT().Get(gomock.Eq("m1")).Return(&domain.Model{ID: "m1", ModelName: "gpt-4"}, nil)
h := NewModelHandler(mockSvc)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
@@ -148,9 +189,13 @@ func TestModelHandler_GetModel(t *testing.T) {
}
func TestModelHandler_UpdateModel(t *testing.T) {
h := NewModelHandler(&mockModelService{
model: &domain.Model{ID: "m1", ModelName: "gpt-4o"},
})
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockSvc := mocks.NewMockModelService(ctrl)
mockSvc.EXPECT().Update(gomock.Eq("m1"), gomock.Any()).Return(nil)
mockSvc.EXPECT().Get(gomock.Eq("m1")).Return(&domain.Model{ID: "m1", ModelName: "gpt-4o"}, nil)
h := NewModelHandler(mockSvc)
body, _ := json.Marshal(map[string]string{"model_name": "gpt-4o"})
w := httptest.NewRecorder()