Passed
Pull Request — master (#111)
by Wouter
02:00
created

FactoryTest::can_create_object()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 0
dl 0
loc 16
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace Zenstruck\Foundry\Tests\Unit;
4
5
use Doctrine\Persistence\ManagerRegistry;
6
use Doctrine\Persistence\ObjectManager;
7
use Faker;
8
use PHPUnit\Framework\TestCase;
0 ignored issues
show
Bug introduced by
The type PHPUnit\Framework\TestCase was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
10
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
11
use Zenstruck\Foundry\Factory;
12
use Zenstruck\Foundry\Proxy;
13
use Zenstruck\Foundry\Test\Factories;
14
use Zenstruck\Foundry\Tests\Fixtures\Entity\Category;
15
use Zenstruck\Foundry\Tests\Fixtures\Entity\Post;
16
17
/**
18
 * @author Kevin Bond <[email protected]>
19
 */
20
final class FactoryTest extends TestCase
21
{
22
    use ExpectDeprecationTrait, Factories;
23
24
    /**
25
     * @test
26
     */
27
    public function can_instantiate_object(): void
28
    {
29
        $attributeArray = ['title' => 'title', 'body' => 'body'];
30
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
Unused Code introduced by
The parameter $faker is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

30
        $attributeCallback = static function(/** @scrutinizer ignore-unused */ Faker\Generator $faker) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
31
            return ['title' => 'title', 'body' => 'body'];
32
        };
33
34
        $this->assertSame('title', (new Factory(Post::class, $attributeArray))->create()->getTitle());
0 ignored issues
show
Bug introduced by
The method getTitle() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

34
        $this->assertSame('title', (new Factory(Post::class, $attributeArray))->create()->/** @scrutinizer ignore-call */ getTitle());
Loading history...
35
        $this->assertSame('title', (new Factory(Post::class))->create($attributeArray)->getTitle());
36
        $this->assertSame('title', (new Factory(Post::class))->withAttributes($attributeArray)->create()->getTitle());
37
        $this->assertSame('title', (new Factory(Post::class, $attributeCallback))->create()->getTitle());
38
        $this->assertSame('title', (new Factory(Post::class))->create($attributeCallback)->getTitle());
39
        $this->assertSame('title', (new Factory(Post::class))->withAttributes($attributeCallback)->create()->getTitle());
40
    }
41
42
    /**
43
     * @test
44
     * @group legacy
45
     */
46
    public function can_instantiate_many_objects_legacy(): void
47
    {
48
        $this->expectDeprecation('Since zenstruck/foundry 1.7: Calling instance method "'.Factory::class.'::createMany()" is deprecated and will be removed in 2.0, use the static "'.Factory::class.':createMany()" method instead.');
49
50
        $attributeArray = ['title' => 'title', 'body' => 'body'];
51
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
Unused Code introduced by
The parameter $faker is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

51
        $attributeCallback = static function(/** @scrutinizer ignore-unused */ Faker\Generator $faker) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
52
            return ['title' => 'title', 'body' => 'body'];
53
        };
54
55
        $objects = (new Factory(Post::class, $attributeArray))->createMany(3);
0 ignored issues
show
Bug introduced by
The method createMany() does not exist on Zenstruck\Foundry\Factory. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        $objects = (new Factory(Post::class, $attributeArray))->/** @scrutinizer ignore-call */ createMany(3);
Loading history...
56
57
        $this->assertCount(3, $objects);
58
        $this->assertSame('title', $objects[0]->getTitle());
59
        $this->assertSame('title', $objects[1]->getTitle());
60
        $this->assertSame('title', $objects[2]->getTitle());
61
62
        $objects = (new Factory(Post::class))->createMany(3, $attributeArray);
63
64
        $this->assertCount(3, $objects);
65
        $this->assertSame('title', $objects[0]->getTitle());
66
        $this->assertSame('title', $objects[1]->getTitle());
67
        $this->assertSame('title', $objects[2]->getTitle());
68
69
        $objects = (new Factory(Post::class))->withAttributes($attributeArray)->createMany(3);
70
71
        $this->assertCount(3, $objects);
72
        $this->assertSame('title', $objects[0]->getTitle());
73
        $this->assertSame('title', $objects[1]->getTitle());
74
        $this->assertSame('title', $objects[2]->getTitle());
75
76
        $objects = (new Factory(Post::class, $attributeCallback))->createMany(3);
77
78
        $this->assertCount(3, $objects);
79
        $this->assertSame('title', $objects[0]->getTitle());
80
        $this->assertSame('title', $objects[1]->getTitle());
81
        $this->assertSame('title', $objects[2]->getTitle());
82
83
        $objects = (new Factory(Post::class))->createMany(3, $attributeCallback);
84
85
        $this->assertCount(3, $objects);
86
        $this->assertSame('title', $objects[0]->getTitle());
87
        $this->assertSame('title', $objects[1]->getTitle());
88
        $this->assertSame('title', $objects[2]->getTitle());
89
90
        $objects = (new Factory(Post::class))->withAttributes($attributeCallback)->createMany(3);
91
92
        $this->assertCount(3, $objects);
93
        $this->assertSame('title', $objects[0]->getTitle());
94
        $this->assertSame('title', $objects[1]->getTitle());
95
        $this->assertSame('title', $objects[2]->getTitle());
96
    }
97
98
    /**
99
     * @test
100
     */
101
    public function can_set_instantiator(): void
102
    {
103
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
104
105
        $object = (new Factory(Post::class))
106
            ->instantiateWith(function(array $attributes, string $class) use ($attributeArray) {
107
                $this->assertSame(Post::class, $class);
108
                $this->assertSame($attributes, $attributeArray);
109
110
                return new Post('title', 'body');
111
            })
112
            ->create($attributeArray)
113
        ;
114
115
        $this->assertSame('title', $object->getTitle());
116
        $this->assertSame('body', $object->getBody());
0 ignored issues
show
Bug introduced by
The method getBody() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
        $this->assertSame('body', $object->/** @scrutinizer ignore-call */ getBody());
Loading history...
117
    }
118
119
    /**
120
     * @test
121
     */
122
    public function can_add_before_instantiate_events(): void
123
    {
124
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
125
126
        $object = (new Factory(Post::class))
127
            ->beforeInstantiate(function(array $attributes) {
128
                $attributes['title'] = 'title';
129
130
                return $attributes;
131
            })
132
            ->beforeInstantiate(function(array $attributes) {
133
                $attributes['body'] = 'body';
134
135
                return $attributes;
136
            })
137
            ->create($attributeArray)
138
        ;
139
140
        $this->assertSame('title', $object->getTitle());
141
        $this->assertSame('body', $object->getBody());
142
    }
143
144
    /**
145
     * @test
146
     */
147
    public function before_instantiate_event_must_return_an_array(): void
148
    {
149
        $this->expectException(\LogicException::class);
150
        $this->expectExceptionMessage('Before Instantiate event callback must return an array.');
151
152
        (new Factory(Post::class))->beforeInstantiate(function() {})->create();
153
    }
154
155
    /**
156
     * @test
157
     */
158
    public function can_add_after_instantiate_events(): void
159
    {
160
        $attributesArray = ['title' => 'title', 'body' => 'body'];
161
162
        $object = (new Factory(Post::class))
163
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
164
                $this->assertSame($attributesArray, $attributes);
165
166
                $post->increaseViewCount();
167
            })
168
            ->afterInstantiate(function(Post $post, array $attributes) use ($attributesArray) {
169
                $this->assertSame($attributesArray, $attributes);
170
171
                $post->increaseViewCount();
172
            })
173
            ->create($attributesArray)
174
        ;
175
176
        $this->assertSame(2, $object->getViewCount());
0 ignored issues
show
Bug introduced by
The method getViewCount() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

176
        $this->assertSame(2, $object->/** @scrutinizer ignore-call */ getViewCount());
Loading history...
177
    }
178
179
    /**
180
     * @test
181
     */
182
    public function can_register_custom_faker(): void
183
    {
184
        $defaultFaker = Factory::faker();
185
        Factory::configuration()->setFaker(Faker\Factory::create());
186
187
        $this->assertNotSame(\spl_object_id(Factory::faker()), \spl_object_id($defaultFaker));
188
    }
189
190
    /**
191
     * @test
192
     */
193
    public function can_register_default_instantiator(): void
194
    {
195
        Factory::configuration()->setInstantiator(function() {
196
            return new Post('different title', 'different body');
197
        });
198
199
        $object = (new Factory(Post::class, ['title' => 'title', 'body' => 'body']))->create();
200
201
        $this->assertSame('different title', $object->getTitle());
202
        $this->assertSame('different body', $object->getBody());
203
    }
204
205
    /**
206
     * @test
207
     */
208
    public function instantiating_with_proxy_attribute_normalizes_to_underlying_object(): void
209
    {
210
        $object = (new Factory(Post::class))->create([
211
            'title' => 'title',
212
            'body' => 'body',
213
            'category' => new Proxy(new Category()),
214
        ]);
215
216
        $this->assertInstanceOf(Category::class, $object->getCategory());
0 ignored issues
show
Bug introduced by
The method getCategory() does not exist on Zenstruck\Foundry\Proxy. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

216
        $this->assertInstanceOf(Category::class, $object->/** @scrutinizer ignore-call */ getCategory());
Loading history...
217
    }
218
219
    /**
220
     * @test
221
     */
222
    public function instantiating_with_factory_attribute_instantiates_the_factory(): void
223
    {
224
        $object = (new Factory(Post::class))->create([
225
            'title' => 'title',
226
            'body' => 'body',
227
            'category' => new Factory(Category::class),
228
        ]);
229
230
        $this->assertInstanceOf(Category::class, $object->getCategory());
231
    }
232
233
    /**
234
     * @test
235
     */
236
    public function factory_is_immutable(): void
237
    {
238
        $factory = new Factory(Post::class);
239
        $objectId = \spl_object_id($factory);
240
241
        $this->assertNotSame(\spl_object_id($factory->withAttributes([])), $objectId);
242
        $this->assertNotSame(\spl_object_id($factory->withoutPersisting()), $objectId);
243
        $this->assertNotSame(\spl_object_id($factory->instantiateWith(function() {})), $objectId);
244
        $this->assertNotSame(\spl_object_id($factory->beforeInstantiate(function() {})), $objectId);
245
        $this->assertNotSame(\spl_object_id($factory->afterInstantiate(function() {})), $objectId);
246
        $this->assertNotSame(\spl_object_id($factory->afterPersist(function() {})), $objectId);
247
    }
248
249
    /**
250
     * @test
251
     */
252
    public function can_create_object(): void
253
    {
254
        $registry = $this->createMock(ManagerRegistry::class);
255
        $registry
256
            ->expects($this->exactly(2))
257
            ->method('getManagerForClass')
258
            ->with(Post::class)
259
            ->willReturn($this->createMock(ObjectManager::class))
260
        ;
261
262
        Factory::configuration()->setManagerRegistry($registry);
263
264
        $object = (new Factory(Post::class))->create(['title' => 'title', 'body' => 'body']);
265
266
        $this->assertInstanceOf(Proxy::class, $object);
267
        $this->assertSame('title', $object->getTitle());
268
    }
269
270
    /**
271
     * @test
272
     * @group legacy
273
     */
274
    public function can_create_many_objects_legacy(): void
275
    {
276
        $this->expectDeprecation('Since zenstruck/foundry 1.7: Calling instance method "'.Factory::class.'::createMany()" is deprecated and will be removed in 2.0, use the static "'.Factory::class.':createMany()" method instead.');
277
278
        $registry = $this->createMock(ManagerRegistry::class);
279
        $registry
280
            ->expects($this->exactly(6))
281
            ->method('getManagerForClass')
282
            ->with(Post::class)
283
            ->willReturn($this->createMock(ObjectManager::class))
284
        ;
285
286
        Factory::configuration()->setManagerRegistry($registry);
287
288
        $objects = (new Factory(Post::class))->createMany(3, ['title' => 'title', 'body' => 'body']);
289
290
        $this->assertCount(3, $objects);
291
        $this->assertInstanceOf(Proxy::class, $objects[0]);
292
        $this->assertInstanceOf(Proxy::class, $objects[1]);
293
        $this->assertInstanceOf(Proxy::class, $objects[2]);
294
        $this->assertSame('title', $objects[0]->getTitle());
295
        $this->assertSame('title', $objects[1]->getTitle());
296
        $this->assertSame('title', $objects[2]->getTitle());
297
    }
298
299
    /**
300
     * @test
301
     */
302
    public function can_add_after_persist_events(): void
303
    {
304
        $registry = $this->createMock(ManagerRegistry::class);
305
        $registry
306
            ->expects($this->exactly(2)) // once for persisting, once for each afterPersist event
307
            ->method('getManagerForClass')
308
            ->with(Post::class)
309
            ->willReturn($this->createMock(ObjectManager::class))
310
        ;
311
312
        Factory::configuration()->setManagerRegistry($registry);
313
314
        $expectedAttributes = ['shortDescription' => 'short desc', 'title' => 'title', 'body' => 'body'];
315
        $calls = 0;
316
317
        $object = (new Factory(Post::class, ['shortDescription' => 'short desc']))
318
            ->afterPersist(function(Proxy $post, array $attributes) use ($expectedAttributes, &$calls) {
319
                /* @var Post $post */
320
                $this->assertSame($expectedAttributes, $attributes);
321
322
                $post->increaseViewCount();
323
                ++$calls;
324
            })
325
            ->afterPersist(function(Post $post, array $attributes) use ($expectedAttributes, &$calls) {
326
                $this->assertSame($expectedAttributes, $attributes);
327
328
                $post->increaseViewCount();
329
                ++$calls;
330
            })
331
            ->afterPersist(function(Post $post, array $attributes) use ($expectedAttributes, &$calls) {
332
                $this->assertSame($expectedAttributes, $attributes);
333
334
                $post->increaseViewCount();
335
                ++$calls;
336
            })
337
            ->afterPersist(function($post) use (&$calls) {
338
                $this->assertInstanceOf(Proxy::class, $post);
339
340
                ++$calls;
341
            })
342
            ->afterPersist(static function() use (&$calls) {
343
                ++$calls;
344
            })
345
            ->create(['title' => 'title', 'body' => 'body'])
346
        ;
347
348
        $this->assertSame(3, $object->getViewCount());
349
        $this->assertSame(5, $calls);
350
    }
351
352
    /**
353
     * @test
354
     */
355
    public function trying_to_persist_without_manager_registry_throws_exception(): void
356
    {
357
        $this->expectException(\RuntimeException::class);
358
        $this->expectExceptionMessage('Foundry was booted without doctrine. Ensure your TestCase extends '.KernelTestCase::class);
359
360
        (new Factory(Post::class))->create(['title' => 'title', 'body' => 'body'])->save();
361
    }
362
}
363