Skip to content

Commit 0abfda5

Browse files
Copilotkevwan
andcommitted
Implement complete test scaffolding with --with-tests flag
Co-authored-by: kevwan <[email protected]>
1 parent 98156e5 commit 0abfda5

File tree

19 files changed

+263
-369
lines changed

19 files changed

+263
-369
lines changed

tools/goctl/api/cmd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func init() {
7676
goCmdFlags.StringVar(&gogen.VarStringHome, "home")
7777
goCmdFlags.StringVar(&gogen.VarStringRemote, "remote")
7878
goCmdFlags.StringVar(&gogen.VarStringBranch, "branch")
79-
goCmdFlags.BoolVar(&gogen.VarBoolWithTest, "test")
79+
goCmdFlags.BoolVar(&gogen.VarBoolWithTest, "with-tests")
8080
goCmdFlags.BoolVar(&gogen.VarBoolTypeGroup, "type-group")
8181
goCmdFlags.StringVarWithDefaultValue(&gogen.VarStringStyle, "style", config.DefaultFormat)
8282

tools/goctl/api/gogen/gen.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ func DoGenProjectWithModule(apiFile, dir, moduleName, style string, withTest boo
118118
if withTest {
119119
logx.Must(genHandlersTest(dir, rootPkg, projectPkg, cfg, api))
120120
logx.Must(genLogicTest(dir, rootPkg, projectPkg, cfg, api))
121+
logx.Must(genServiceContextTest(dir, rootPkg, projectPkg, cfg, api))
122+
logx.Must(genIntegrationTest(dir, rootPkg, projectPkg, cfg, api))
121123
}
122124

123125
if err := backupAndSweep(apiFile); err != nil {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package gogen
2+
3+
import (
4+
_ "embed"
5+
6+
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
7+
"github.com/zeromicro/go-zero/tools/goctl/config"
8+
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
9+
"github.com/zeromicro/go-zero/tools/goctl/util/format"
10+
)
11+
12+
//go:embed integration_test.tpl
13+
var integrationTestTemplate string
14+
15+
func genIntegrationTest(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiSpec) error {
16+
serviceName := api.Service.Name
17+
if len(serviceName) == 0 {
18+
serviceName = "server"
19+
}
20+
21+
filename, err := format.FileNamingFormat(cfg.NamingFormat, serviceName)
22+
if err != nil {
23+
return err
24+
}
25+
26+
return genFile(fileGenConfig{
27+
dir: dir,
28+
subdir: "",
29+
filename: filename + "_test.go",
30+
templateName: "integrationTestTemplate",
31+
category: category,
32+
templateFile: integrationTestTemplateFile,
33+
builtinTemplate: integrationTestTemplate,
34+
data: map[string]any{
35+
"projectPkg": projectPkg,
36+
"serviceName": serviceName,
37+
"version": version.BuildVersion,
38+
"hasRoutes": len(api.Service.Routes()) > 0,
39+
"routes": api.Service.Routes(),
40+
},
41+
})
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package gogen
2+
3+
import (
4+
_ "embed"
5+
6+
"github.com/zeromicro/go-zero/tools/goctl/api/spec"
7+
"github.com/zeromicro/go-zero/tools/goctl/config"
8+
"github.com/zeromicro/go-zero/tools/goctl/internal/version"
9+
"github.com/zeromicro/go-zero/tools/goctl/util/format"
10+
)
11+
12+
//go:embed svc_test.tpl
13+
var svcTestTemplate string
14+
15+
func genServiceContextTest(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiSpec) error {
16+
filename, err := format.FileNamingFormat(cfg.NamingFormat, contextFilename)
17+
if err != nil {
18+
return err
19+
}
20+
21+
return genFile(fileGenConfig{
22+
dir: dir,
23+
subdir: contextDir,
24+
filename: filename + "_test.go",
25+
templateName: "svcTestTemplate",
26+
category: category,
27+
templateFile: svcTestTemplateFile,
28+
builtinTemplate: svcTestTemplate,
29+
data: map[string]any{
30+
"projectPkg": projectPkg,
31+
"version": version.BuildVersion,
32+
},
33+
})
34+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Code scaffolded by goctl. Safe to edit.
2+
// goctl {{.version}}
3+
4+
package main
5+
6+
import (
7+
"net/http"
8+
"net/http/httptest"
9+
"testing"
10+
"time"
11+
12+
"{{.projectPkg}}/internal/config"
13+
"{{.projectPkg}}/internal/handler"
14+
"{{.projectPkg}}/internal/svc"
15+
16+
"github.com/stretchr/testify/assert"
17+
"github.com/stretchr/testify/require"
18+
"github.com/zeromicro/go-zero/rest"
19+
)
20+
21+
func TestMain(m *testing.M) {
22+
// TODO: Add setup/teardown logic here if needed
23+
m.Run()
24+
}
25+
26+
func TestServerIntegration(t *testing.T) {
27+
// Create test server
28+
c := config.Config{
29+
RestConf: rest.RestConf{
30+
Host: "127.0.0.1",
31+
Port: 0, // Use random available port
32+
},
33+
}
34+
35+
server := rest.MustNewServer(c.RestConf)
36+
defer server.Stop()
37+
38+
ctx := svc.NewServiceContext(c)
39+
handler.RegisterHandlers(server, ctx)
40+
41+
// Start server in background
42+
go func() {
43+
server.Start()
44+
}()
45+
46+
// Wait for server to start
47+
time.Sleep(100 * time.Millisecond)
48+
49+
tests := []struct {
50+
name string
51+
method string
52+
path string
53+
body string
54+
expectedStatus int
55+
setup func()
56+
}{
57+
{
58+
name: "health check",
59+
method: "GET",
60+
path: "/health",
61+
expectedStatus: http.StatusNotFound, // Adjust based on actual routes
62+
setup: func() {},
63+
},
64+
{{if .hasRoutes}}{{range .routes}}{
65+
name: "{{.Method}} {{.Path}}",
66+
method: "{{.Method}}",
67+
path: "{{.Path}}",
68+
expectedStatus: http.StatusOK, // TODO: Adjust expected status
69+
setup: func() {
70+
// TODO: Add setup logic for this endpoint
71+
},
72+
},
73+
{{end}}{{end}}{
74+
name: "not found route",
75+
method: "GET",
76+
path: "/nonexistent",
77+
expectedStatus: http.StatusNotFound,
78+
setup: func() {},
79+
},
80+
}
81+
82+
for _, tt := range tests {
83+
t.Run(tt.name, func(t *testing.T) {
84+
tt.setup()
85+
86+
req, err := http.NewRequest(tt.method, tt.path, nil)
87+
require.NoError(t, err)
88+
89+
rr := httptest.NewRecorder()
90+
server.ServeHTTP(rr, req)
91+
92+
assert.Equal(t, tt.expectedStatus, rr.Code)
93+
94+
// TODO: Add response body assertions
95+
t.Logf("Response: %s", rr.Body.String())
96+
})
97+
}
98+
}
99+
100+
func TestServerLifecycle(t *testing.T) {
101+
c := config.Config{
102+
RestConf: rest.RestConf{
103+
Host: "127.0.0.1",
104+
Port: 0,
105+
},
106+
}
107+
108+
server := rest.MustNewServer(c.RestConf)
109+
110+
// Test server can start and stop without errors
111+
ctx := svc.NewServiceContext(c)
112+
handler.RegisterHandlers(server, ctx)
113+
114+
// In a real integration test, you might start the server in a goroutine
115+
// and test actual HTTP requests, but for scaffolding we keep it simple
116+
server.Stop()
117+
118+
// TODO: Add more lifecycle tests as needed
119+
assert.True(t, true, "Server lifecycle test passed")
120+
}

tools/goctl/api/gogen/svc_test.tpl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Code scaffolded by goctl. Safe to edit.
2+
// goctl {{.version}}
3+
4+
package svc
5+
6+
import (
7+
"testing"
8+
9+
"{{.projectPkg}}/internal/config"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestNewServiceContext(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
config config.Config
18+
setup func() config.Config
19+
}{
20+
{
21+
name: "default config",
22+
setup: func() config.Config {
23+
return config.Config{}
24+
},
25+
},
26+
{
27+
name: "valid config",
28+
setup: func() config.Config {
29+
return config.Config{
30+
// TODO: Add valid config values here
31+
}
32+
},
33+
},
34+
}
35+
36+
for _, tt := range tests {
37+
t.Run(tt.name, func(t *testing.T) {
38+
c := tt.setup()
39+
svcCtx := NewServiceContext(c)
40+
41+
// Basic assertions
42+
require.NotNil(t, svcCtx)
43+
assert.Equal(t, c, svcCtx.Config)
44+
45+
// TODO: Add additional assertions for middleware and dependencies
46+
})
47+
}
48+
}
49+
50+
func TestServiceContext_Initialization(t *testing.T) {
51+
c := config.Config{}
52+
svcCtx := NewServiceContext(c)
53+
54+
// Verify service context is properly initialized
55+
assert.NotNil(t, svcCtx)
56+
assert.Equal(t, c, svcCtx.Config)
57+
58+
// TODO: Add tests for middleware initialization if any
59+
// TODO: Add tests for external dependencies if any
60+
}

tools/goctl/api/gogen/template.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ const (
2222
routesTemplateFile = "routes.tpl"
2323
routesAdditionTemplateFile = "route-addition.tpl"
2424
typesTemplateFile = "types.tpl"
25+
svcTestTemplateFile = "svc_test.tpl"
26+
integrationTestTemplateFile = "integration_test.tpl"
2527
)
2628

2729
var templates = map[string]string{
@@ -39,6 +41,8 @@ var templates = map[string]string{
3941
routesTemplateFile: routesTemplate,
4042
routesAdditionTemplateFile: routesAdditionTemplate,
4143
typesTemplateFile: typesTemplate,
44+
svcTestTemplateFile: svcTestTemplate,
45+
integrationTestTemplateFile: integrationTestTemplate,
4246
}
4347

4448
// Category returns the category of the api files.

tools/goctl/api/gogen/workspace/a.go

Lines changed: 0 additions & 34 deletions
This file was deleted.

tools/goctl/api/gogen/workspace/etc/a-api.yaml

Lines changed: 0 additions & 3 deletions
This file was deleted.

tools/goctl/api/gogen/workspace/go.mod

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)