Skip to content

Commit 27b4d7f

Browse files
authored
feat: allow ModelFactory::findOrCreate() in unit tests (#461)
1 parent 68c6a5e commit 27b4d7f

File tree

5 files changed

+45
-10
lines changed

5 files changed

+45
-10
lines changed

src/Configuration.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Doctrine\Persistence\ObjectManager;
1717
use Faker;
1818
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
19+
use Zenstruck\Foundry\Exception\FoundryBootException;
1920

2021
/**
2122
* @internal
@@ -241,10 +242,13 @@ public function getOdmObjectManagersToReset(): array
241242
return $this->odmObjectManagersToReset;
242243
}
243244

245+
/**
246+
* @throws FoundryBootException
247+
*/
244248
private function managerRegistry(): ?ManagerRegistry
245249
{
246250
if (!$this->hasManagerRegistry()) {
247-
throw new \RuntimeException('Foundry was booted without doctrine. Ensure your TestCase extends '.KernelTestCase::class);
251+
throw FoundryBootException::notBootedWithDoctrine();
248252
}
249253

250254
return $this->managerRegistry;

src/Exception/FoundryNotBootedException.php renamed to src/Exception/FoundryBootException.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,29 @@
1111

1212
namespace Zenstruck\Foundry\Exception;
1313

14+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
15+
1416
/**
1517
* @internal
1618
*/
17-
final class FoundryNotBootedException extends \RuntimeException
19+
final class FoundryBootException extends \RuntimeException
1820
{
19-
public function __construct()
21+
private function __construct(string $message)
22+
{
23+
parent::__construct($message);
24+
}
25+
26+
public static function notBootedYet(): self
2027
{
21-
parent::__construct(
28+
return new self(
2229
'Foundry is not yet booted. Using in a test: is your Test case using the Factories trait? Using in a fixture: is ZenstruckFoundryBundle enabled for this environment?'
2330
);
2431
}
32+
33+
public static function notBootedWithDoctrine(): self
34+
{
35+
return new self(
36+
'Foundry was booted without doctrine. Ensure your TestCase extends '.KernelTestCase::class
37+
);
38+
}
2539
}

src/Factory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Doctrine\ORM\EntityManagerInterface;
1616
use Doctrine\ORM\Mapping\ClassMetadata as ORMClassMetadata;
1717
use Faker;
18-
use Zenstruck\Foundry\Exception\FoundryNotBootedException;
18+
use Zenstruck\Foundry\Exception\FoundryBootException;
1919
use Zenstruck\Foundry\Persistence\InversedRelationshipCascadePersistCallback;
2020
use Zenstruck\Foundry\Persistence\PostPersistCallback;
2121

@@ -291,13 +291,13 @@ final public static function shutdown(): void
291291
}
292292

293293
/**
294+
* @throws FoundryBootException
294295
* @internal
295-
* @throws FoundryNotBootedException
296296
*/
297297
final public static function configuration(): Configuration
298298
{
299299
if (!self::isBooted()) {
300-
throw new FoundryNotBootedException();
300+
throw FoundryBootException::notBootedYet();
301301
}
302302

303303
return self::$configuration; // @phpstan-ignore-line
@@ -315,7 +315,7 @@ final public static function faker(): Faker\Generator
315315
{
316316
try {
317317
return self::configuration()->faker();
318-
} catch (FoundryNotBootedException $exception) {
318+
} catch (FoundryBootException $exception) {
319319
throw new \RuntimeException("Cannot get Foundry's configuration. If using faker in a data provider, consider passing attributes as a callable.");
320320
}
321321
}

src/ModelFactory.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Zenstruck\Foundry;
1313

14+
use Zenstruck\Foundry\Exception\FoundryBootException;
15+
1416
/**
1517
* @template TModel of object
1618
* @template-extends Factory<TModel>
@@ -106,8 +108,11 @@ final public static function createSequence(iterable|callable $sequence): array
106108
*/
107109
final public static function findOrCreate(array $attributes): Proxy
108110
{
109-
if ($found = static::repository()->find($attributes)) {
110-
return $found;
111+
try {
112+
if ($found = static::repository()->find($attributes)) {
113+
return $found;
114+
}
115+
} catch (FoundryBootException) {
111116
}
112117

113118
return static::new()->create($attributes);

tests/Unit/ModelFactoryTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,16 @@ public function create_with_many_to_many_relation(): void
116116
$this->assertNull($post->getId());
117117
$this->assertCount(3, $post->getTags());
118118
}
119+
120+
/**
121+
* @test
122+
*/
123+
public function can_call_find_or_create(): void
124+
{
125+
$post = PostFactory::findOrCreate([
126+
'title' => 'foo',
127+
]);
128+
129+
$this->assertSame('foo', $post->getTitle());
130+
}
119131
}

0 commit comments

Comments
 (0)