diff --git a/README.md b/README.md index 8ebfe60..9cc7d12 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Go Dependency Injection with Generics ## Example +### Struct + configuration.go ```go @@ -97,3 +99,125 @@ func main() { println(msgService.Welcome()) } ``` + +### Interface + +message_service.go + +```go +package main + +import "git.apihub24.de/admin/generic-di" + +func init() { + di.Injectable(newMessageService) +} + +type IMessageService interface { + Welcome() string +} + +type messageService struct { + greeter *Greeter +} + +func NewMessageService() IMessageService { + return &messageService{ + // here was the Greeter from greeter.go injected + greeter: di.Inject[*Greeter](), + } +} + +func (ctx *messageService) Welcome() string { + return ctx.greeter.Greet() +} +``` + +main.go + +```go +package main + +import di "git.apihub24.de/admin/generic-di" + +func main() { + msgService := di.Inject[IMessageService]() + // prints the message "Hello, Markus" + println(msgService.Welcome()) +} +``` + +## Replace Instance + +services/message_service.go + +```go +package services + +import "git.apihub24.de/admin/generic-di" + +func init() { + di.Injectable(newMessageService) +} + +type IMessageService interface { + Welcome() string +} + +type messageService struct { + greeter *Greeter +} + +func NewMessageService() IMessageService { + return &messageService{ + // here was the Greeter from greeter.go injected + greeter: di.Inject[*Greeter](), + } +} + +func (ctx *messageService) Welcome() string { + return ctx.greeter.Greet() +} +``` + +main.go + +```go +package main + +import di "git.apihub24.de/admin/generic-di" + +func main() { + msgService := di.Inject[services.IMessageService]() + // prints the message "Hello, Markus" + println(msgService.Welcome()) +} +``` + +message_service_test.go + +```go +package services_test + +func init() { + // replace the instance of IMessageService with the Mock + di.Replace(newMessageServiceMock) +} + +type messageServiceMock struct {} + +func newMessageServiceMock() services.IMessageService { + return &messageServiceMock{} +} + +func (svc *messageServiceMock) Welcome() string { + return "Hello, Mock" +} + +func TestMessageServiceMocking(t *testing.T) { + service := di.Inject[services.IMessageService]() + if service.Welcome() != "Hello, Mock" { + t.Errorf("expect Hello, Mock but get %s", service.Welcome()) + } +} +``` diff --git a/injector.go b/injector.go index 66265dd..feaaabb 100644 --- a/injector.go +++ b/injector.go @@ -21,6 +21,22 @@ func Injectable[T any](creator func() T) { } } +func Replace[T any](creator func() T, identifier ...string) { + Injectable(creator) + selector := getSelector[T]() + instanceSelector := getSelector[T](identifier...) + cre, creatorExists := creators[selector] + if !creatorExists { + return + } + createdInstance, instanceCreated := cre().(T) + if instanceCreated { + instanceMutex.Lock() + defer instanceMutex.Unlock() + instances[instanceSelector] = createdInstance + } +} + // Inject gets or create a Instance of the Struct used the Injectable constructor Function func Inject[T any](identifier ...string) T { var nilResult T diff --git a/injector_test.go b/injector_test.go index af90237..dc8710c 100644 --- a/injector_test.go +++ b/injector_test.go @@ -13,6 +13,7 @@ func init() { di.Injectable(newMessageService) di.Injectable(newConfiguration) di.Injectable(newGreetingService) + di.Injectable(newBasicOverridableService) } type ( @@ -30,8 +31,33 @@ type ( Greeting() string TakeID() string } + + overridableService interface { + GetInstanceID() string + GetValue() string + } + + basicOverridableService struct { + id string + } + + basicOverridableServiceMock struct { + id string + } ) +func newBasicOverridableService() overridableService { + return &basicOverridableService{ + id: uuid.NewString(), + } +} + +func newBasicOverridableServiceMock() overridableService { + return &basicOverridableServiceMock{ + id: uuid.NewString(), + } +} + func newConfiguration() *configuration { return &configuration{} } @@ -53,6 +79,22 @@ func newMessageService() *messageService { } } +func (ctx *basicOverridableService) GetInstanceID() string { + return ctx.id +} + +func (ctx *basicOverridableService) GetValue() string { + return "i am original" +} + +func (ctx *basicOverridableServiceMock) GetInstanceID() string { + return ctx.id +} + +func (ctx *basicOverridableServiceMock) GetValue() string { + return "i am mock" +} + func (ctx *configuration) GetUserName() string { return "Markus" } @@ -134,6 +176,22 @@ func TestTryInterface_MultipleInstances(t *testing.T) { } } +func TestOverwriteInjectable(t *testing.T) { + basic := di.Inject[overridableService]() + basicID := basic.GetInstanceID() + if basic.GetValue() != "i am original" { + t.Errorf("wrong service instance get") + } + di.Replace(newBasicOverridableServiceMock) + basic = di.Inject[overridableService]() + if basic.GetInstanceID() == basicID { + t.Errorf("basic and newOne are the same instance") + } + if basic.GetValue() != "i am mock" { + t.Errorf("service not overwritten") + } +} + func TestDestroy(t *testing.T) { _ = di.Inject[textService]("a") di.Destroy[textService]("a")