Skip to content

Commit 7593c26

Browse files
committed
Added tests for atesting
ok github.com/go-autowire/autowire/atesting 0.504s coverage: 100.0% of statements Signed-off-by: Filip Petrov <[email protected]>
1 parent 999eaac commit 7593c26

File tree

15 files changed

+232
-195
lines changed

15 files changed

+232
-195
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,16 @@
77
[release]: https://github.com/go-autowire/autowire
88

99
[report-card-img]: https://goreportcard.com/badge/github.com/go-autowire/autowire
10-
[report-card]: https://goreportcard.com/report/github.com/go-autowire/autowire
10+
[report-card]: https://goreportcard.com/report/github.com/go-autowire/autowire
11+
12+
Reflection based dependency injection toolkit for Golang.
13+
14+
This README is in working in progress state.
15+
16+
## Installation
17+
18+
The whole project is based on go modules.
19+
To get the latest version, use go1.16+ and fetch it using the go get command. For example:
20+
```bash
21+
go get github.com/go-autowire/autowire
22+
```

atesting/testing.go

Lines changed: 29 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,27 @@ package atesting
33

44
import (
55
"container/list"
6+
. "github.com/go-autowire/autowire"
7+
"github.com/go-autowire/autowire/internal"
68
"log"
79
"reflect"
8-
"unicode"
9-
10-
"github.com/go-autowire/autowire"
1110
)
1211

13-
// Spy Function is replacing object field with the one provided in the function as a second argument.
14-
// Spy Function detects automatically which field could be replaced with the provided one.
15-
// Important note: In order to traverse fields of the unexported fields we need to implement Getters.
16-
// As shown inside example package, we are replacing AuditClient with our mock implementation and in order to reach this
17-
// field we need Getter.
12+
// Spy Function is replacing object field with the one provided in the function as a variadic arguments.
13+
// Spy Function will detect fully automatically which field could be replaced
14+
// with the provided one as variadic arguments.
15+
// As shown inside example package, we are replacing AuditClient with our mock implementation.
1816
// Example:
19-
// atesting.Spy(application, &TestAuditClient{})
20-
// Or this is equivalent of
17+
// Spy(application, &TestAuditClient{})
18+
// Or this is equivalent of doing it manually
2119
// application.UserSvc().SetAuditClient(&TestAuditClient{})
22-
// Getter UserSvc() is used to access userSvc field, which is unexported.
23-
// For more information take a look at example package.
20+
// When we don't use Spy function, we need to provide Getter method UserSvc() in order to
21+
// access unexported userSvc field.
22+
// For more information take a look at test file in example package.
2423
// Parameters of Spy function:
25-
// - `v` : pointer to structure inside which spy object will be applied
26-
// - `dependency` : pointer to structure which will be injected
27-
func Spy(v interface{}, dependency interface{}) {
28-
slice := []interface{}{dependency}
29-
Spies(v, slice)
30-
}
31-
32-
// Spies Function is replacing object fields with the list of provided dependencies
33-
// in the function as a second argument. Spy Function detects automatically which field
34-
// could be replaced with the provided one in the list of dependencies.
35-
// Important note: In order to traverse fields of the unexported fields we need to implement Getters.
36-
// As shown inside example package, we are replacing AuditClient with our mock implementation and in order to reach this
37-
// field we need Getter.
38-
// Example:
39-
// atesting.Spies(application, []interface{}{&TestPaymentServiceTest{}, &TestAuditClient{}})
40-
// Or this is equivalent of
41-
// application.UserSvc().SetAuditClient(&TestAuditClient{})
42-
// application.UserSvc().PaymentSvc = &TestPaymentServiceTest{}
43-
// Getter UserSvc() is used to access userSvc field, which is unexported. In case of PaymentSvc it is not required
44-
// as field PaymentSvc is exported.
45-
// Parameters of Spies function:
46-
// - `v` : structure inside which spy objects will be applied
47-
// - `dependencies` : list of dependencies which will be injected
48-
// For more information take a look at example package.
49-
func Spies(v interface{}, dependencies []interface{}) {
24+
// - `v` : pointer to structure inside which spy object will be injected
25+
// - `dependencies` : this is variadic argument, pointer to mocked structures which are gonna be injected
26+
func Spy(v interface{}, dependencies ...interface{}) {
5027
queue := list.New()
5128
queue.PushBack(v)
5229
for queue.Len() > 0 {
@@ -57,56 +34,37 @@ func Spies(v interface{}, dependencies []interface{}) {
5734
switch value.Kind() {
5835
case reflect.Ptr:
5936
elem = value.Elem()
60-
case reflect.Struct:
61-
elem = value
6237
}
6338
for i := 0; i < elem.NumField(); i++ {
6439
field := elem.Type().Field(i)
65-
tag, ok := field.Tag.Lookup(autowire.Tag)
40+
tag, ok := field.Tag.Lookup(Tag)
6641
if ok {
6742
if tag != "" {
68-
for _, dependency := range dependencies {
69-
dependValue := reflect.ValueOf(dependency)
43+
for _, currentDependency := range dependencies {
44+
dependValue := reflect.ValueOf(currentDependency)
7045
if dependValue.Type().Implements(field.Type) {
7146
t := reflect.New(dependValue.Type())
72-
log.Println("Injecting Spy on dependency by tag " + tag + " will be used " + t.Type().String())
73-
autowire.Autowire(dependency)
74-
setFieldValue(value, elem, i, dependency)
47+
log.Println("Injecting Spy on currentDependency by tag " + tag + " will be used " + t.Type().String())
48+
Autowire(currentDependency)
49+
internal.SetFieldValue(elem, i, currentDependency)
50+
}
51+
}
52+
} else {
53+
for _, currentDependency := range dependencies {
54+
log.Printf("Checking compatability between %s & %s", reflect.TypeOf(currentDependency), elem.Field(i).Type())
55+
if reflect.TypeOf(currentDependency) == elem.Field(i).Type() {
56+
internal.SetFieldValue(elem, i, currentDependency)
7557
}
7658
}
7759
}
7860
if !elem.Field(i).IsNil() {
7961
if elem.Field(i).Elem().CanInterface() {
80-
queue.PushBack(autowire.Autowired(elem.Field(i).Elem().Interface()))
62+
queue.PushBack(Autowired(elem.Field(i).Elem().Interface()))
8163
} else {
82-
runeName := []rune(elem.Type().Field(i).Name)
83-
runeName[0] = unicode.ToUpper(runeName[0])
84-
methodName := string(runeName)
85-
method := value.MethodByName(methodName)
86-
if method.IsValid() {
87-
result := method.Call([]reflect.Value{})[0]
88-
queue.PushBack(autowire.Autowired(result.Interface()))
89-
}
64+
queue.PushBack(Autowired(internal.GetUnexportedField(elem.Field(i))))
9065
}
9166
}
9267
}
9368
}
9469
}
9570
}
96-
97-
func setFieldValue(value reflect.Value, elem reflect.Value, i int, dependency interface{}) bool {
98-
runeName := []rune(elem.Type().Field(i).Name)
99-
exported := unicode.IsUpper(runeName[0])
100-
if exported {
101-
elem.Field(i).Set(reflect.ValueOf(dependency))
102-
} else {
103-
runeName[0] = unicode.ToUpper(runeName[0])
104-
methodName := "Set" + string(runeName)
105-
method := value.MethodByName(methodName)
106-
if method.IsValid() {
107-
method.Call([]reflect.Value{reflect.ValueOf(dependency)})
108-
return true
109-
}
110-
}
111-
return false
112-
}

atesting/testing_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package atesting_test
2+
3+
import (
4+
. "github.com/go-autowire/autowire"
5+
. "github.com/go-autowire/autowire/atesting"
6+
"github.com/stretchr/testify/assert"
7+
"testing"
8+
)
9+
10+
type FooEr interface {
11+
Foo()
12+
}
13+
14+
// A Foo represent named struct
15+
type Foo struct {
16+
Name string
17+
CloseCalls int
18+
}
19+
20+
// Pass method
21+
func (f Foo) Foo() {
22+
}
23+
24+
type BarEr interface {
25+
Baz()
26+
}
27+
28+
// Foo represent named struct
29+
type Bar struct {
30+
Name string
31+
CloseCalls int
32+
}
33+
34+
// Pass method
35+
func (b Bar) Baz() {
36+
}
37+
38+
// A FooBarUnexported represent named struct
39+
type FooBarUnexported struct {
40+
foo *Foo `autowire:""`
41+
bar *Bar `autowire:""`
42+
}
43+
44+
// A FooBar represent named struct
45+
type FooBar struct {
46+
Foo *Foo `autowire:""`
47+
Bar *Bar `autowire:""`
48+
}
49+
50+
// Baz represent named struct
51+
type Baz struct {
52+
MyFoo FooEr `autowire:"Foo"`
53+
MyBaz BarEr `autowire:"Bar"`
54+
}
55+
56+
func TestSpyUnexportedStructPtr(t *testing.T) {
57+
fooName := "foo"
58+
Autowire(&Foo{Name: fooName})
59+
barName := "bar"
60+
Autowire(&Bar{Name: barName})
61+
tmpFooBar := &FooBarUnexported{}
62+
Autowire(tmpFooBar)
63+
assert.Equal(t, tmpFooBar.foo.Name, fooName)
64+
assert.Equal(t, tmpFooBar.bar.Name, barName)
65+
testFooName := "testFoo"
66+
testBarName := "testBar"
67+
Spy(tmpFooBar, &Foo{Name: testFooName}, &Bar{Name: testBarName})
68+
assert.Equal(t, tmpFooBar.foo.Name, testFooName)
69+
assert.Equal(t, tmpFooBar.bar.Name, testBarName)
70+
assert.Equal(t, 0, len(Close()))
71+
}
72+
73+
func TestSpyExportedStructPtr(t *testing.T) {
74+
fooName := "foo"
75+
Autowire(&Foo{Name: fooName})
76+
barName := "bar"
77+
Autowire(&Bar{Name: barName})
78+
tmpFooBar := &FooBar{}
79+
Autowire(tmpFooBar)
80+
assert.Equal(t, tmpFooBar.Foo.Name, fooName)
81+
assert.Equal(t, tmpFooBar.Bar.Name, barName)
82+
testFooName := "testFoo"
83+
testBarName := "testBar"
84+
Spy(tmpFooBar, &Foo{Name: testFooName}, &Bar{Name: testBarName})
85+
assert.Equal(t, tmpFooBar.Foo.Name, testFooName)
86+
assert.Equal(t, tmpFooBar.Bar.Name, testBarName)
87+
assert.Equal(t, 0, len(Close()))
88+
}
89+
90+
func TestSpyInterface(t *testing.T) {
91+
fooName := "foo"
92+
Autowire(&Foo{Name: fooName})
93+
barName := "bar"
94+
Autowire(&Bar{Name: barName})
95+
tmpBaz := &Baz{}
96+
Autowire(tmpBaz)
97+
assert.Equal(t, tmpBaz.MyFoo.(*Foo).Name, fooName)
98+
assert.Equal(t, tmpBaz.MyBaz.(*Bar).Name, barName)
99+
testFooName := "testFoo"
100+
testBarName := "testBar"
101+
Spy(tmpBaz, &Foo{Name: testFooName}, &Bar{Name: testBarName})
102+
assert.Equal(t, tmpBaz.MyFoo.(*Foo).Name, testFooName)
103+
assert.Equal(t, tmpBaz.MyBaz.(*Bar).Name, testBarName)
104+
assert.Equal(t, 0, len(Close()))
105+
}

0 commit comments

Comments
 (0)