1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace KochTest\DI; |
4
|
|
|
|
5
|
|
|
use Koch\DI\DependencyInjector; |
6
|
|
|
use Koch\DI\Lifecycle\Reused; |
7
|
|
|
|
8
|
|
|
class DependencyInjectorTest extends \PHPUnit_Framework_TestCase |
9
|
|
|
{ |
10
|
|
|
/** |
11
|
|
|
* @var DependencyInjector |
12
|
|
|
*/ |
13
|
|
|
protected $object; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Sets up the fixture, for example, opens a network connection. |
17
|
|
|
* This method is called before a test is executed. |
18
|
|
|
*/ |
19
|
|
|
protected function setUp() |
20
|
|
|
{ |
21
|
|
|
$this->object = new DependencyInjector(); |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Tears down the fixture, for example, closes a network connection. |
26
|
|
|
* This method is called after a test is executed. |
27
|
|
|
*/ |
28
|
|
|
protected function tearDown() |
29
|
|
|
{ |
30
|
|
|
unset($this->object); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @covers Koch\DI\DependencyInjector::register |
35
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
36
|
|
|
* @covers Koch\DI\DependencyInjector::register |
37
|
|
|
*/ |
38
|
|
|
public function testRegister() |
39
|
|
|
{ |
40
|
|
|
include_once __DIR__ . '/fixtures/ClassForSingletonInstantiationTest.php'; |
41
|
|
|
|
42
|
|
|
// instantiate as singleton |
43
|
|
|
$this->object->register(new Reused('KochTest\DI\CreateMeOnce')); |
44
|
|
|
$this->assertSame( |
45
|
|
|
$this->object->instantiate('KochTest\DI\CreateMeOnce'), |
46
|
|
|
$this->object->instantiate('KochTest\DI\CreateMeOnce') |
47
|
|
|
); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @covers Koch\DI\DependencyInjector::forVariable |
52
|
|
|
* @covers Koch\DI\DependencyInjector::register |
53
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
54
|
|
|
* @covers Koch\DI\Engine\Variable::willUse |
55
|
|
|
*/ |
56
|
|
|
public function testForVariable() |
57
|
|
|
{ |
58
|
|
|
include_once __DIR__ . '/fixtures/ClassesForInjectionOfVariablesTest.php'; |
59
|
|
|
|
60
|
|
|
// test variable injection |
61
|
|
|
$this->object->forVariable('first')->willUse('KochTest\DI\NeededForFirst'); |
62
|
|
|
$this->object->forVariable('second')->willUse('KochTest\DI\NeededForSecond'); |
63
|
|
|
$this->assertEquals( |
64
|
|
|
$this->object->instantiate('KochTest\DI\VariablesInConstructor'), |
65
|
|
|
new VariablesInConstructor( |
66
|
|
|
new NeededForFirst(), |
67
|
|
|
new NeededForSecond() |
68
|
|
|
) |
69
|
|
|
); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @covers Koch\DI\DependencyInjector::whenCreating |
74
|
|
|
* @covers Koch\DI\Engine\Context::wrapWith |
75
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
76
|
|
|
*/ |
77
|
|
|
public function testWhenCreating() |
78
|
|
|
{ |
79
|
|
|
include_once __DIR__ . '/fixtures/ClassesForWhenCreatingTest.php'; |
80
|
|
|
|
81
|
|
|
// 1) create concrete implemenation BareImplemenation via interface Bare |
82
|
|
|
// and 2) do a constructor injection of Bare into WrapperForBare |
83
|
|
|
$this->object->whenCreating('KochTest\DI\Bare')->wrapWith('KochTest\DI\WrapperForBare'); |
84
|
|
|
|
85
|
|
|
$this->assertEquals( |
86
|
|
|
$this->object->instantiate('KochTest\DI\Bare'), |
87
|
|
|
new WrapperForBare(new BareImplementation()) |
88
|
|
|
); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* @covers Koch\DI\DependencyInjector::forType |
93
|
|
|
* @covers Koch\DI\Engine\Type::call |
94
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
95
|
|
|
*/ |
96
|
|
|
public function testForType() |
97
|
|
|
{ |
98
|
|
|
include_once __DIR__ . '/fixtures/ClassesForSetterInjectionTest.php'; |
99
|
|
|
|
100
|
|
|
// test can call setters to complete initialisation |
101
|
|
|
$this->object->forType('KochTest\DI\NeedsInitToCompleteConstruction')->call('init'); |
102
|
|
|
$expected = new NeedsInitToCompleteConstruction(); |
103
|
|
|
$expected->init(new NotWithoutMe()); // <-- setter injection |
104
|
|
|
$this->assertEquals( |
105
|
|
|
$this->object->instantiate('KochTest\DI\NeedsInitToCompleteConstruction'), |
106
|
|
|
$expected |
107
|
|
|
); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @covers Koch\DI\DependencyInjector::fill |
112
|
|
|
* @covers Koch\DI\DependencyInjector::with |
113
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
114
|
|
|
*/ |
115
|
|
|
public function testFill() |
116
|
|
|
{ |
117
|
|
|
include_once __DIR__ . '/fixtures/ClassForParameterInjectionTest.php'; |
118
|
|
|
|
119
|
|
|
// can fill missing parameters with explicit values |
120
|
|
|
$this->assertEquals( |
121
|
|
|
$this->object->fill('a', 'b')->with(3, 5)->instantiate('KochTest\DI\ClassWithParameters'), |
122
|
|
|
new ClassWithParameters(3, 5) |
123
|
|
|
); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* @covers Koch\DI\DependencyInjector::with |
128
|
|
|
* @covers Koch\DI\DependencyInjector::fill |
129
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
130
|
|
|
*/ |
131
|
|
|
public function testWith() |
132
|
|
|
{ |
133
|
|
|
include_once __DIR__ . '/fixtures/ClassForParameterInjectionTest.php'; |
134
|
|
|
|
135
|
|
|
// 1) can fill missing parameters with explicit values |
136
|
|
|
$this->assertEquals( |
137
|
|
|
$this->object->with(3, 5)->instantiate('KochTest\DI\ClassWithParameters'), |
138
|
|
|
new ClassWithParameters(3, 5) |
139
|
|
|
); |
140
|
|
|
|
141
|
|
|
// 2) can instantiate with named parameters |
142
|
|
|
$this->assertEquals( |
143
|
|
|
$this->object->fill('a', 'b')->with(3, 5)->instantiate('KochTest\DI\ClassWithParameters'), |
144
|
|
|
new ClassWithParameters(3, 5) |
145
|
|
|
); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
150
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
151
|
|
|
* @covers Koch\DI\DependencyInjector::register |
152
|
|
|
* @covers Koch\DI\DependencyInjector::forVariable |
153
|
|
|
* @covers Koch\DI\DependencyInjector::forType |
154
|
|
|
* @covers Koch\DI\Engine\Type::call |
155
|
|
|
* @covers Koch\DI\Engine\Variable::willUse |
156
|
|
|
*/ |
157
|
|
|
public function testCreate() |
158
|
|
|
{ |
159
|
|
|
include_once __DIR__ . '/fixtures/ClassesForInjectionOfTypeHintsTest.php'; |
160
|
|
|
|
161
|
|
|
// test injection of simple dependencies |
162
|
|
|
$this->assertEquals( |
163
|
|
|
$this->object->instantiate('KochTest\DI\HintedConstructor'), |
164
|
|
|
new HintedConstructor( |
165
|
|
|
new NeededForConstructor() |
166
|
|
|
) |
167
|
|
|
); |
168
|
|
|
|
169
|
|
|
// test repeated type hint injection |
170
|
|
|
$this->object->register('KochTest\DI\SecondImplementation'); |
171
|
|
|
$this->assertEquals( |
172
|
|
|
$this->object->instantiate('KochTest\DI\RepeatedHintConstructor'), |
173
|
|
|
new RepeatedHintConstructor( |
174
|
|
|
new NeededForConstructor(), |
175
|
|
|
new NeededForConstructor() |
176
|
|
|
) |
177
|
|
|
); |
178
|
|
|
|
179
|
|
|
include_once __DIR__ . '/fixtures/ClassForParameterInjectionTest.php'; |
180
|
|
|
|
181
|
|
|
// test create with parameters |
182
|
|
|
// this is a short syntax form of the test #1 in testWith() |
183
|
|
|
$this->assertEquals( |
184
|
|
|
$this->object->instantiate('KochTest\DI\ClassWithParameters', 3, 5), |
185
|
|
|
new ClassWithParameters(3, 5) |
186
|
|
|
); |
187
|
|
|
|
188
|
|
|
include_once __DIR__ . '/fixtures/ClassForInjectionOfSpecificValuesTest.php'; |
189
|
|
|
|
190
|
|
|
// test inject specific instance |
191
|
|
|
$this->object->register(new Thing()); |
192
|
|
|
$this->assertEquals( |
193
|
|
|
$this->object->instantiate('KochTest\DI\WrapThing'), |
194
|
|
|
new WrapThing(new Thing()) |
195
|
|
|
); |
196
|
|
|
|
197
|
|
|
// test injecting specific instance for named variable |
198
|
|
|
$this->object->forVariable('thing')->willUse(new Thing()); |
199
|
|
|
$this->assertEquals( |
200
|
|
|
$this->object->instantiate('KochTest\DI\WrapAnything'), |
201
|
|
|
new WrapAnything(new Thing()) |
202
|
|
|
); |
203
|
|
|
|
204
|
|
|
// test injecting non-object |
205
|
|
|
$this->object->forVariable('thing')->willUse(100); |
206
|
|
|
$this->assertEquals( |
207
|
|
|
$this->object->instantiate('KochTest\DI\WrapAnything'), |
208
|
|
|
new WrapAnything(100) |
209
|
|
|
); |
210
|
|
|
|
211
|
|
|
// test injection string @todo |
212
|
|
|
/* $this->object->forVariable('thing')->useString('100'); |
|
|
|
|
213
|
|
|
$this->assertEquals( |
214
|
|
|
$this->object->instantiate('KochTest\DI\WrapAnything'), new WrapAnything('100') |
215
|
|
|
); */ |
216
|
|
|
|
217
|
|
|
include_once __DIR__ . '/fixtures/ClassesForAutoInstantiationTest.php'; |
218
|
|
|
|
219
|
|
|
// test named class instantiated automatically |
220
|
|
|
$this->assertInstanceOf('KochTest\DI\LoneClass', $this->object->instantiate('KochTest\DI\LoneClass')); |
221
|
|
|
|
222
|
|
|
// test will use only subclass if parent class is abstract class |
223
|
|
|
$this->assertInstanceOf( |
224
|
|
|
'KochTest\DI\ConcreteSubclass', |
225
|
|
|
$this->object->instantiate('KochTest\DI\AbstractClass') |
226
|
|
|
); |
227
|
|
|
|
228
|
|
|
// test can be configured to prefer a specific subclass |
229
|
|
|
$this->object->register('KochTest\DI\SecondSubclass'); |
230
|
|
|
$this->assertInstanceOf( |
231
|
|
|
'KochTest\DI\SecondSubclass', |
232
|
|
|
$this->object->instantiate('KochTest\DI\ClassWithManySubclasses') |
233
|
|
|
); |
234
|
|
|
|
235
|
|
|
include_once __DIR__ . '/fixtures/ClassesForInterfaceInstantiationTest.php'; |
236
|
|
|
|
237
|
|
|
$this->assertInstanceOf( |
238
|
|
|
'KochTest\DI\OnlyImplementation', $this->object->instantiate('KochTest\DI\InterfaceWithOneImplementation') |
239
|
|
|
); |
240
|
|
|
|
241
|
|
|
// can be configured to prefer specific implementation |
242
|
|
|
$this->object->register('KochTest\DI\SecondImplementation'); |
243
|
|
|
$this->assertInstanceOf( |
244
|
|
|
'KochTest\DI\SecondImplementation', |
245
|
|
|
$this->object->instantiate('KochTest\DI\InterfaceWithManyImplementations') |
246
|
|
|
); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
251
|
|
|
* @expectedException Koch\DI\Exception\CannotFindImplementation |
252
|
|
|
* @expectedExceptionMessage InterfaceWithManyImplementations |
253
|
|
|
*/ |
254
|
|
|
public function testCreateCreatingInterfaceWithManyImplementationsThrowsException() |
255
|
|
|
{ |
256
|
|
|
include_once __DIR__ . '/fixtures/ClassesForInterfaceInstantiationTest.php'; |
257
|
|
|
|
258
|
|
|
$this->object->instantiate('InterfaceWithManyImplementations'); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* @covers Koch\DI\DependencyInjector::instantiate |
263
|
|
|
* @expectedException Koch\DI\Exception\CannotFindImplementation |
264
|
|
|
* @expectedExceptionMessage NonExistingClass |
265
|
|
|
*/ |
266
|
|
|
public function testCreateCreatingNonExistingClassThrowsException() |
267
|
|
|
{ |
268
|
|
|
$this->object->instantiate('NonExistingClass'); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* @covers Koch\DI\DependencyInjector::pickFactory |
273
|
|
|
* @expectedException \Koch\DI\Exception\CannotDetermineImplementation |
274
|
|
|
*/ |
275
|
|
|
public function testPickFactory() |
276
|
|
|
{ |
277
|
|
|
$type = ''; |
278
|
|
|
$candidates = ''; |
279
|
|
|
$this->object->pickFactory($type, $candidates); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* @covers Koch\DI\DependencyInjector::settersFor |
284
|
|
|
*/ |
285
|
|
|
public function testSettersFor() |
286
|
|
|
{ |
287
|
|
|
$class = ''; |
288
|
|
|
$this->assertEquals([], $this->object->settersFor($class)); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* @covers Koch\DI\DependencyInjector::wrappersFor |
293
|
|
|
*/ |
294
|
|
|
public function testWrappersFor() |
295
|
|
|
{ |
296
|
|
|
$type = ''; |
297
|
|
|
$this->assertEquals([], $this->object->wrappersFor($type)); |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* @covers Koch\DI\DependencyInjector::useParameters |
302
|
|
|
*/ |
303
|
|
|
public function testUseParameters() |
304
|
|
|
{ |
305
|
|
|
$parameters = ['A' => '1']; |
306
|
|
|
$this->object->useParameters($parameters); |
307
|
|
|
$this->assertEquals($parameters, $this->object->named_parameters); |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* @covers Koch\DI\DependencyInjector::instantiateParameter |
312
|
|
|
*/ |
313
|
|
|
public function testInstantiateParameter() |
314
|
|
|
{ |
315
|
|
|
// prepare param 1 |
316
|
|
|
$parameter = $this->getMock('parameter', ['getName']); |
317
|
|
|
// Calling $parameter->getName() will now return 'name'. |
|
|
|
|
318
|
|
|
$parameter->expects($this->any())->method('getName')->will($this->returnValue('name')); |
319
|
|
|
// prepare param 2 |
320
|
|
|
$nesting = ''; |
321
|
|
|
// prepare class |
322
|
|
|
$this->object->named_parameters['name'] = 'someValue'; |
323
|
|
|
|
324
|
|
|
$erv = $this->object->instantiateParameter($parameter, $nesting); |
325
|
|
|
|
326
|
|
|
$this->assertEquals('someValue', $erv); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* @covers Koch\DI\DependencyInjector::instantiateParameter |
331
|
|
|
* @expectedException Koch\DI\Exception\MissingDependency |
332
|
|
|
* @expectedExceptionMessage theMissingDependency |
333
|
|
|
*/ |
334
|
|
|
public function testInstantiateParameterThrowsException() |
335
|
|
|
{ |
336
|
|
|
// prepare param 1 |
337
|
|
|
$parameter = $this->getMock('parameter', ['getName']); |
338
|
|
|
// Calling $parameter->getName() will now return 'name'. |
|
|
|
|
339
|
|
|
$parameter->expects($this->any())->method('getName')->will($this->returnValue('theMissingDependency')); |
340
|
|
|
// prepare param 2 |
341
|
|
|
$nesting = ''; |
342
|
|
|
|
343
|
|
|
$erv = $this->object->instantiateParameter($parameter, $nesting); |
344
|
|
|
|
345
|
|
|
$this->assertEquals('someValue', $erv); |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
/** |
349
|
|
|
* @covers Koch\DI\DependencyInjector::repository |
350
|
|
|
*/ |
351
|
|
|
public function testRepository() |
352
|
|
|
{ |
353
|
|
|
$this->assertEquals($this->object->repository, $this->object->repository()); |
354
|
|
|
} |
355
|
|
|
} |
356
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.