狂欢依赖注入
Revel Dependency Injection
我希望让我的 revel 控制器使用各种服务,我模拟这些服务以进行单元测试。我是新来的;在 C# 中,我会使用依赖注入来注入它们。在 revel 中有通用的方法吗?
我发现的最好方法似乎是在控制器的 Before() 方法中初始化真实服务(可能使用有线解决的方法),并在测试的 Before() 中设置模拟版本( ) 方法。或者有更好的方法吗?
其实GO有很多DI系统。我已经搜索了几个,尝试使用并最终选择了一个带有一些补丁的更方便的。用法很简单:
package dependency
import (
"fmt"
"github.com/lisitsky/inject"
)
func init() {
inject.Provide(NewStringer)
}
type stringer struct{}
func (s stringer) String() string {
return "Hello, World"
}
func NewStringer() fmt.Stringer {
return stringer{}
}
接受依赖的一方(main.go):
package main
import (
"fmt"
"github.com/lisitsky/inject"
_ "github.com/lisitsky/inject/examples/simple/dependency"
)
var (
str fmt.Stringer
)
func main() {
inject.Construct(&str)
fmt.Println("My Stringer is:", str)
}
还支持延迟初始化:
func main() {
// define variables to be constructed later
inject.ConstructLater(&str)
// define dependency providers
inject.Provide(NewStringer)
// finalize construction - all DI variables would be initialized at one call
injector.FinishConstruct()
fmt.Println("My Stringer is:", str)
}
我使用 filter 来注入依赖项。
过滤器测试控制器是否实现特定接口并填充正确的依赖项。这是一个插入与数据库相关的依赖项的示例:
func DependencyFilter(c *revel.Controller, filterChain []revel.Filter) {
if ctrl, ok := c.AppController.(DataServiceController); ok {
ctrl.SetDataService(<your dependency>)
}
// Different dependencies could be injected here:
//if ctrl, ok := c.AppController.(FooController); ok {
// ctrl.SetFooService(<your dependency>)
//}
// Call the next filter
if len(filterChain) > 0 {
filterChain[0](c, filterChain[1:])
}
}
其中 DataServiceController
是:
type DataServiceController interface {
SetDataService(ds services.DataService)
}
我将过滤器作为倒数第二个条目插入 init.go
:
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
// ...
DependencyFilter, // Add dependencies
revel.ActionInvoker, // Invoke the action.
}
我的大部分控制器都需要相同的依赖项,所以我有一个它们都嵌入的基本控制器:
type BaseController struct {
*revel.Controller
DataService services.DataService
}
func (c *BaseController) SetDataService(ds services.DataService) {
c.DataService = ds
}
所以我的具体控制器是这样的:
type Home struct {
BaseController
}
func (c Home) Index() revel.Result {
// ...
}
可能有更好的方法,但这是我的方法。
我希望让我的 revel 控制器使用各种服务,我模拟这些服务以进行单元测试。我是新来的;在 C# 中,我会使用依赖注入来注入它们。在 revel 中有通用的方法吗?
我发现的最好方法似乎是在控制器的 Before() 方法中初始化真实服务(可能使用有线解决的方法),并在测试的 Before() 中设置模拟版本( ) 方法。或者有更好的方法吗?
其实GO有很多DI系统。我已经搜索了几个,尝试使用并最终选择了一个带有一些补丁的更方便的。用法很简单:
package dependency
import (
"fmt"
"github.com/lisitsky/inject"
)
func init() {
inject.Provide(NewStringer)
}
type stringer struct{}
func (s stringer) String() string {
return "Hello, World"
}
func NewStringer() fmt.Stringer {
return stringer{}
}
接受依赖的一方(main.go):
package main
import (
"fmt"
"github.com/lisitsky/inject"
_ "github.com/lisitsky/inject/examples/simple/dependency"
)
var (
str fmt.Stringer
)
func main() {
inject.Construct(&str)
fmt.Println("My Stringer is:", str)
}
还支持延迟初始化:
func main() {
// define variables to be constructed later
inject.ConstructLater(&str)
// define dependency providers
inject.Provide(NewStringer)
// finalize construction - all DI variables would be initialized at one call
injector.FinishConstruct()
fmt.Println("My Stringer is:", str)
}
我使用 filter 来注入依赖项。
过滤器测试控制器是否实现特定接口并填充正确的依赖项。这是一个插入与数据库相关的依赖项的示例:
func DependencyFilter(c *revel.Controller, filterChain []revel.Filter) {
if ctrl, ok := c.AppController.(DataServiceController); ok {
ctrl.SetDataService(<your dependency>)
}
// Different dependencies could be injected here:
//if ctrl, ok := c.AppController.(FooController); ok {
// ctrl.SetFooService(<your dependency>)
//}
// Call the next filter
if len(filterChain) > 0 {
filterChain[0](c, filterChain[1:])
}
}
其中 DataServiceController
是:
type DataServiceController interface {
SetDataService(ds services.DataService)
}
我将过滤器作为倒数第二个条目插入 init.go
:
revel.Filters = []revel.Filter{
revel.PanicFilter, // Recover from panics and display an error page instead.
// ...
DependencyFilter, // Add dependencies
revel.ActionInvoker, // Invoke the action.
}
我的大部分控制器都需要相同的依赖项,所以我有一个它们都嵌入的基本控制器:
type BaseController struct {
*revel.Controller
DataService services.DataService
}
func (c *BaseController) SetDataService(ds services.DataService) {
c.DataService = ds
}
所以我的具体控制器是这样的:
type Home struct {
BaseController
}
func (c Home) Index() revel.Result {
// ...
}
可能有更好的方法,但这是我的方法。