Completed
Push — master ( 3728bb...c02760 )
by Taosikai
12:33
created

ContainerTest::testSetWithShare()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 19
nc 1
nop 0
1
<?php
2
namespace Slince\Di\Tests;
3
4
use Slince\Di\Container;
5
use Slince\Di\Definition;
6
use Slince\Di\Exception\DependencyInjectionException;
7
use Slince\Di\Reference;
8
use Slince\Di\Tests\TestClass\Actor;
9
use Slince\Di\Tests\TestClass\ActorInterface;
10
use Slince\Di\Tests\TestClass\Actress;
11
use Slince\Di\Tests\TestClass\Director;
12
use Slince\Di\Tests\TestClass\Movie;
13
14
error_reporting(E_ALL ^ E_USER_DEPRECATED);
15
16
class ContainerTest extends \PHPUnit_Framework_TestCase
17
{
18
    public function getContainer()
19
    {
20
        return new Container();
21
    }
22
23
    /**
24
     * 自定义闭包或者工厂方法代理
25
     */
26
    public function testDelegate()
27
    {
28
        $container = $this->getContainer();
29
        $container->delegate('director1', function () {
30
            return new Director('James', 26);
31
        });
32
        $this->assertInstanceOf(Director::class, $container->get('director1'));
33
        $container->delegate('director2', [Director::class, 'factory']); //或者 'Slince\Di\Tests\TestClass\Director::factory'
34
        $this->assertInstanceOf(Director::class, $container->get('director2'));
35
    }
36
37
    /**
38
     * 测试对象绑定,对象绑定结果是单例
39
     */
40
    public function testInstance()
41
    {
42
        $container = $this->getContainer();
43
        $director = new Director();
44
        $container->instance('director', $director);
45
        $this->assertInstanceOf(Director::class, $container->get('director'));
46
        $this->assertTrue($container->get('director') === $director);
47
        //instance只能是单例
48
        $this->assertTrue($container->get('director') === $container->get('director'));
49
    }
50
51
    public function testDefine()
52
    {
53
        $container = $this->getContainer();
54
        $container->define('director', Director::class, [0 => 'Bob', 1 => 45]);
55
        $this->assertInstanceOf(Director::class, $director = $container->get('director'));
56
        $this->assertEquals('Bob', $director->getName());
57
        $this->assertEquals(45, $director->getAge());
58
    }
59
60
    /**
61
     * @deprecated
62
     */
63
    public function testSetDefinition()
64
    {
65
        $container = $this->getContainer();
66
        $container->setDefinition('director', new Definition(Director::class, [
67
            'name' => 'Bob',
68
            'age' => 45
69
        ]));
70
        $this->assertInstanceOf(Director::class, $director = $container->get('director'));
71
        $this->assertEquals('Bob', $director->getName());
72
        $this->assertEquals(45, $director->getAge());
73
    }
74
75
    /**
76
     * 类名<=>别名,interface <=> implement绑定
77
     */
78
    public function testSimpleBind()
79
    {
80
        $container = $this->getContainer();
81
        //简单的别名绑定
82
        $container->bind('director', Director::class);
83
        $this->assertInstanceOf(Director::class, $container->get('director'));
84
    }
85
86
    /**
87
     * {@deprecated}
88
     */
89
    public function alias()
90
    {
91
        $container = $this->getContainer();
92
        //兼容旧版本别名绑定
93
        $container->alias('director', Director::class);
94
        $this->assertInstanceOf(Director::class, $container->get('director'));
95
    }
96
97
    /**
98
     * 绑定接口与实现
99
     */
100
    public function testInterfaceBind()
101
    {
102
        $container = $this->getContainer();
103
        //接口与实现;类绑定
104
        $container->bind(ActorInterface::class, Actor::class);
105
        //直接获取接口实例
106
        $this->assertInstanceOf(ActorInterface::class, $container->get(ActorInterface::class));
107
        $this->assertInstanceOf(Actor::class, $container->get(ActorInterface::class));
108
109
        //获取依赖该接口的类实例
110
        $movie = $container->get(Movie::class);
111
        $this->assertInstanceOf(Movie::class, $movie);
112
        $this->assertInstanceOf(Actor::class, $movie->getActor());
113
    }
114
115
    /**
116
     * 为类设置接口依赖
117
     */
118
    public function testInterfaceBindForClassContext()
119
    {
120
        $container = $this->getContainer();
121
        //为Movie类声明接口实际指向
122
        $container->bind(ActorInterface::class, Actor::class, Movie::class);
123
        //获取依赖该接口的类实例,由于构造方法与setter皆是类依赖故container可以自动解决
124
        $container->define('movie', Movie::class, [], [
125
            'setActress' => []
126
        ]);
127
128
        $movie = $container->get('movie');
129
        $this->assertInstanceOf(Movie::class, $movie);
130
        $this->assertInstanceOf(Actor::class, $movie->getActor());
131
        $this->assertInstanceOf(Actor::class, $movie->getActress());
132
133
        //直接获取接口实例,会报出异常
134
        $this->setExpectedException(DependencyInjectionException::class);
135
        $this->assertInstanceOf(Actor::class, $container->get(ActorInterface::class));
136
    }
137
138
    /**
139
     * 为类方法设置接口依赖
140
     */
141
    public function testInterfaceBindForClassMethodContext()
142
    {
143
        $container = $this->getContainer();
144
        //为Movie类声明接口依赖
145
        $container->bind(ActorInterface::class, Actor::class, [Movie::class, '__construct']); //构造函数
146
        $container->bind(ActorInterface::class, Actress::class, [Movie::class, 'setActress']); //setter方法
147
148
        //获取依赖该接口的类实例,由于构造方法与setter皆是类依赖故container可以自动解决
149
        $container->define('movie', Movie::class, [], [
150
            'setActress' => []
151
        ]);
152
        $movie = $container->get('movie');
153
        $this->assertInstanceOf(Movie::class, $movie);
154
        $this->assertInstanceOf(Actor::class, $movie->getActor());
155
        $this->assertInstanceOf(Actress::class, $movie->getActress());
156
    }
157
158
    public function testShare()
159
    {
160
        $container = $this->getContainer();
161
        $container->delegate('director', function () {
162
            return new Director('James', 26);
163
        });
164
        $container->share('director');
165
        $this->assertInstanceOf(Director::class, $container->get('director'));
166
        $this->assertTrue($container->get('director') === $container->get('director'));
167
168
        //兼容旧的api,已提示废除
169
        $container->share('director2', function () {
170
            return new Director('James', 26);
171
        });
172
        $this->assertTrue($container->get('director2') === $container->get('director2'));
173
    }
174
175
    public function testSet()
176
    {
177
        $container = $this->getContainer();
178
        //Similar to delegate
179
        $container->set('director', function () {
180
            return new Director('James', 26);
181
        });
182
        $this->assertInstanceOf(Director::class, $container->get('director'));
183
        $this->assertFalse($container->get('director') === $container->get('director'));
184
185
        //Similar to bind
186
        $container->set('director2', Director::class);
187
        $this->assertInstanceOf(Director::class, $container->get('director2'));
188
        $this->assertFalse($container->get('director2') === $container->get('director2'));
189
190
        //Similar to instance
191
        $container->set('director3', new Director());
192
        $this->assertInstanceOf(Director::class, $container->get('director3'));
193
        $this->assertTrue($container->get('director3') === $container->get('director3'));
194
195
        //Similar to define
196
        $container->set('director4', new Definition(Director::class, [
197
            'name' => 'Bob',
198
            'age' => 45
199
        ]));
200
        $this->assertInstanceOf(Director::class, $container->get('director4'));
201
        $this->assertFalse($container->get('director4') === $container->get('director4'));
202
    }
203
204
    public function testSetWithShare()
205
    {
206
        $container = $this->getContainer();
207
        //Similar to delegate
208
        $container->set('director', function () {
209
            return new Director('James', 26);
210
        }, true);
211
        $this->assertInstanceOf(Director::class, $container->get('director'));
212
        $this->assertTrue($container->get('director') === $container->get('director'));
213
214
        //Similar to bind
215
        $container->set('director2', Director::class, true);
216
        $this->assertInstanceOf(Director::class, $container->get('director2'));
217
        $this->assertTrue($container->get('director2') === $container->get('director2'));
218
219
        //Similar to instance
220
        $container->set('director3', new Director(), true);
221
        $this->assertInstanceOf(Director::class, $container->get('director3'));
222
        $this->assertTrue($container->get('director3') === $container->get('director3'));
223
224
        //Similar to define
225
        $container->set('director4', new Definition(Director::class, [
226
            'name' => 'Bob',
227
            'age' => 45
228
        ]), true);
229
        $this->assertInstanceOf(Director::class, $container->get('director4'));
230
        $this->assertTrue($container->get('director4') === $container->get('director4'));
231
    }
232
233
    public function testGetWithArguments()
234
    {
235
        $container = $this->getContainer();
236
        $director = $container->get(Director::class, [
237
            'age' => 26
238
        ]);
239
        //变量名索引
240
        $this->assertEquals(26, $director->getAge());
241
        //数字索引
242
        $director = $container->get(Director::class, [
243
            1 => 18
244
        ]);
245
        $this->assertEquals(18, $director->getAge());
246
    }
247
248
    public function testGetWithReference()
249
    {
250
        $container = $this->getContainer();
251
        $container->set('director', new Director('Bob', 45));
252
        $container->bind(ActorInterface::class, Actor::class);
253
254
        $movie = $container->get(Movie::class);
255
        $this->assertEquals(18, $movie->getDirector()->getAge()); //Defaults age
256
257
        $movie = $container->get(Movie::class, [
258
            new Reference('director')
259
        ]);
260
        $this->assertEquals('Bob', $movie->getDirector()->getName());
261
        $this->assertEquals(45, $movie->getDirector()->getAge());
262
    }
263
264
    public function testSimpleGlobalParameter()
265
    {
266
        $container = $this->getContainer();
267
        $container->setParameters([
268
            'directorName' => 'James'
269
        ]);
270
        $container->delegate('director', function (Container $container) {
271
            return new Director($container->getParameter('directorName'), 26);
272
        });
273
        $this->assertEquals('James', $container->get('director')->getName());
274
    }
275
276
    public function testGlobalParameter()
277
    {
278
        $container = $this->getContainer();
279
        $container->setParameters([
280
            'directorName' => 'James',
281
            'director' => [ //支持点号获取深度数据结构
282
                'age' => 26
283
            ]
284
        ]);
285
        //支持点号访问
286
        $container->define('director', Director::class, [
287
            '%directorName%',
288
            '%director.age%'
289
        ]);
290
        $this->assertEquals('James', $container->get('director')->getName());
291
        $this->assertEquals(26, $container->get('director')->getAge());
292
293
        //在get操作时传入参数
294
        $this->assertEquals(26, $container->get(Director::class, [
295
            'age' => '%director.age%'
296
        ])->getAge());
297
    }
298
}
299