Issues (131)

tests/Unit/FactoryTest.php (8 issues)

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
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\AnonymousFactory;
12
use Zenstruck\Foundry\Factory;
13
use Zenstruck\Foundry\Proxy;
14
use Zenstruck\Foundry\Test\Factories;
15
use Zenstruck\Foundry\Tests\Fixtures\Entity\Category;
16
use Zenstruck\Foundry\Tests\Fixtures\Entity\Post;
17
18
/**
19
 * @author Kevin Bond <[email protected]>
20
 */
21
final class FactoryTest extends TestCase
22
{
23
    use ExpectDeprecationTrait, Factories;
24
25
    /**
26
     * @test
27
     */
28
    public function can_instantiate_object(): void
29
    {
30
        $attributeArray = ['title' => 'title', 'body' => 'body'];
31
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
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

31
        $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...
32
            return ['title' => 'title', 'body' => 'body'];
33
        };
34
35
        $this->assertSame('title', (new AnonymousFactory(Post::class, $attributeArray))->create()->getTitle());
0 ignored issues
show
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

35
        $this->assertSame('title', (new AnonymousFactory(Post::class, $attributeArray))->create()->/** @scrutinizer ignore-call */ getTitle());
Loading history...
36
        $this->assertSame('title', (new AnonymousFactory(Post::class))->create($attributeArray)->getTitle());
37
        $this->assertSame('title', (new AnonymousFactory(Post::class))->withAttributes($attributeArray)->create()->getTitle());
38
        $this->assertSame('title', (new AnonymousFactory(Post::class, $attributeCallback))->create()->getTitle());
39
        $this->assertSame('title', (new AnonymousFactory(Post::class))->create($attributeCallback)->getTitle());
40
        $this->assertSame('title', (new AnonymousFactory(Post::class))->withAttributes($attributeCallback)->create()->getTitle());
41
    }
42
43
    /**
44
     * @test
45
     * @group legacy
46
     */
47
    public function can_instantiate_many_objects_legacy(): void
48
    {
49
        $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.');
50
51
        $attributeArray = ['title' => 'title', 'body' => 'body'];
52
        $attributeCallback = static function(Faker\Generator $faker) {
0 ignored issues
show
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

52
        $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...
53
            return ['title' => 'title', 'body' => 'body'];
54
        };
55
56
        $objects = (new Factory(Post::class, $attributeArray))->createMany(3);
0 ignored issues
show
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

56
        $objects = (new Factory(Post::class, $attributeArray))->/** @scrutinizer ignore-call */ createMany(3);
Loading history...
57
58
        $this->assertCount(3, $objects);
59
        $this->assertSame('title', $objects[0]->getTitle());
60
        $this->assertSame('title', $objects[1]->getTitle());
61
        $this->assertSame('title', $objects[2]->getTitle());
62
63
        $objects = (new Factory(Post::class))->createMany(3, $attributeArray);
64
65
        $this->assertCount(3, $objects);
66
        $this->assertSame('title', $objects[0]->getTitle());
67
        $this->assertSame('title', $objects[1]->getTitle());
68
        $this->assertSame('title', $objects[2]->getTitle());
69
70
        $objects = (new Factory(Post::class))->withAttributes($attributeArray)->createMany(3);
71
72
        $this->assertCount(3, $objects);
73
        $this->assertSame('title', $objects[0]->getTitle());
74
        $this->assertSame('title', $objects[1]->getTitle());
75
        $this->assertSame('title', $objects[2]->getTitle());
76
77
        $objects = (new Factory(Post::class, $attributeCallback))->createMany(3);
78
79
        $this->assertCount(3, $objects);
80
        $this->assertSame('title', $objects[0]->getTitle());
81
        $this->assertSame('title', $objects[1]->getTitle());
82
        $this->assertSame('title', $objects[2]->getTitle());
83
84
        $objects = (new Factory(Post::class))->createMany(3, $attributeCallback);
85
86
        $this->assertCount(3, $objects);
87
        $this->assertSame('title', $objects[0]->getTitle());
88
        $this->assertSame('title', $objects[1]->getTitle());
89
        $this->assertSame('title', $objects[2]->getTitle());
90
91
        $objects = (new Factory(Post::class))->withAttributes($attributeCallback)->createMany(3);
92
93
        $this->assertCount(3, $objects);
94
        $this->assertSame('title', $objects[0]->getTitle());
95
        $this->assertSame('title', $objects[1]->getTitle());
96
        $this->assertSame('title', $objects[2]->getTitle());
97
    }
98
99
    /**
100
     * @test
101
     */
102
    public function can_set_instantiator(): void
103
    {
104
        $attributeArray = ['title' => 'original title', 'body' => 'original body'];
105
106
        $object = (new AnonymousFactory(Post::class))
107
            ->instantiateWith(function(array $attributes, string $class) use ($attributeArray) {
108
                $this->assertSame(Post::class, $class);
109
                $this->assertSame($attributes, $attributeArray);
110
111
                return new Post('title', 'body');
112
            })
113
            ->create($attributeArray)
114
        ;
115
116
        $this->assertSame('title', $object->getTitle());
117
        $this->assertSame('body', $object->getBody());
0 ignored issues
show
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

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

177
        $this->assertSame(2, $object->/** @scrutinizer ignore-call */ getViewCount());
Loading history...
178
    }
179
180
    /**
181
     * @test
182
     */
183
    public function can_register_custom_faker(): void
184
    {
185
        $defaultFaker = Factory::faker();
186
        Factory::configuration()->setFaker(Faker\Factory::create());
187
188
        $this->assertNotSame(\spl_object_id(Factory::faker()), \spl_object_id($defaultFaker));
189
    }
190
191
    /**
192
     * @test
193
     */
194
    public function can_register_default_instantiator(): void
195
    {
196
        Factory::configuration()->setInstantiator(function() {
197
            return new Post('different title', 'different body');
198
        });
199
200
        $object = (new AnonymousFactory(Post::class, ['title' => 'title', 'body' => 'body']))->create();
201
202
        $this->assertSame('different title', $object->getTitle());
203
        $this->assertSame('different body', $object->getBody());
204
    }
205
206
    /**
207
     * @test
208
     */
209
    public function instantiating_with_proxy_attribute_normalizes_to_underlying_object(): void
210
    {
211
        $object = (new AnonymousFactory(Post::class))->create([
212
            'title' => 'title',
213
            'body' => 'body',
214
            'category' => new Proxy(new Category()),
215
        ]);
216
217
        $this->assertInstanceOf(Category::class, $object->getCategory());
0 ignored issues
show
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

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