我不认为这个问题有单一的回应,但我会分享我的方法,我目前正在做的依赖注入Go-go-gin(但应该是几乎与任何其他路由器)。
从业务角度来看,我有一个结构体,它包含所有对我的服务的访问,这些服务负责业务规则/处理。
// WchyContext is an application-wide context
type WchyContext struct {
Health services.HealthCheckService
Tenant services.TenantService
... whatever
}
我的服务就是接口。
// HealthCheckService is a simple general purpose health check service
type HealthCheckService interface {
IsDatabaseOnline() bool
}
有哪些多张的实现,如MockedHealthCheck
,PostgresHealthCheck
,PostgresTenantService
等。
我的路由器不是取决于WchyContext,其代码如下所示:
func GetMainEngine(ctx context.WchyContext) *gin.Engine {
router := gin.New()
router.Use(gin.Logger())
router.GET("/status", Status(ctx))
router.GET("/tenants/:domain", TenantByDomain(ctx))
return router
}`
Status
和TenantByDomain
行为像一个处理工厂,它的作用是创建一个基于给定的背景下,新的处理程序,像这样的:
type statusHandler struct {
ctx context.WchyContext
}
// Status creates a new Status HTTP handler
func Status(ctx context.WchyContext) gin.HandlerFunc {
return statusHandler{ctx: ctx}.get()
}
func (h statusHandler) get() gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(200, gin.H{
"healthy": gin.H{
"database": h.ctx.Health.IsDatabaseOnline(),
},
"now": time.Now().Format("2006.01.02.150405"),
})
}
}
正如你看到的,我的健康检查的处理程序并不关心具体落实我的服务,我只是用它无论是在ctx.
最后一部分取决于当前的执行环境。在自动化测试中,我创建一个新的WchyContext
使用嘲笑/存根服务并将其发送到GetMainEngine,像这样:
ctx := context.WchyContext{
Health: &services.InMemoryHealthCheckService{Status: false},
Tenant: &services.InMemoryTenantService{Tenants: []*models.Tenant{
&models.Tenant{ID: 1, Name: "Orange Inc.", Domain: "orange"},
&models.Tenant{ID: 2, Name: "The Triathlon Shop", Domain: "trishop"},
}}
}
router := handlers.GetMainEngine(ctx)
request, _ := http.NewRequest(method, url, nil)
response := httptest.NewRecorder()
router.ServeHTTP(response, request)
... check if response matches what you expect from your handler
当你安装它去倾听一个HTTP端口,布线了这个样子的:
var ctx context.WchyContext
var db *sql.DB
func init() {
db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
ctx = context.WchyContext{
Health: &services.PostgresHealthCheckService{DB: db},
Tenant: &services.PostgresTenantService{DB: db}
}
}
func main() {
handlers.GetMainEngine(ctx).Run(":" + util.GetEnvOrDefault("PORT", "3000"))
}
有几件事我不喜欢这件事,我可能会在稍后重构/改进它,但它迄今运行良好。
如果你想看到完整的代码参考,我在做这个项目在这里https://github.com/WeCanHearYou/wchy
希望它可以帮助你以某种方式。
请参阅https://godoc.org/net/http/httptest#Server –