Skip to content

Commit 4cb1568

Browse files
authored
Adds ModelFactory support for hyperf/testing (#5894)
1 parent b2fb337 commit 4cb1568

File tree

4 files changed

+178
-1
lines changed

4 files changed

+178
-1
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"hyperf/utils": "~3.1.0",
3333
"symfony/http-foundation": "^5.4|^6.0"
3434
},
35+
"suggest": {
36+
"fakerphp/faker": "Required to use Faker feature.(^1.23)"
37+
},
3538
"extra": {
3639
"branch-alias": {
3740
"dev-master": "3.0-dev"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Testing\Concerns;
13+
14+
use Faker\Factory as FakerFactory;
15+
use Hyperf\Testing\ModelFactory;
16+
17+
trait InteractsWithModelFactory
18+
{
19+
protected ?ModelFactory $modelFactory = null;
20+
21+
protected string|array $factoryPath = BASE_PATH . '/database/factories';
22+
23+
protected function setUpInteractsWithModelFactory()
24+
{
25+
if (! class_exists(FakerFactory::class)) {
26+
return;
27+
}
28+
29+
$this->modelFactory = ModelFactory::create(
30+
FakerFactory::create('en_US')
31+
);
32+
33+
foreach ((array) $this->factoryPath as $path) {
34+
if (is_dir($path)) {
35+
$this->modelFactory->load($path);
36+
}
37+
}
38+
}
39+
40+
protected function tearDownInteractsWithModelFactory()
41+
{
42+
$this->modelFactory = null;
43+
}
44+
}

src/ModelFactory.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Testing;
13+
14+
use Faker\Generator;
15+
use Hyperf\Database\Model\Factory;
16+
17+
/**
18+
* @template T
19+
*/
20+
class ModelFactory
21+
{
22+
public function __construct(protected Factory $factory)
23+
{
24+
}
25+
26+
public static function create(Generator $faker)
27+
{
28+
return new static(new Factory($faker));
29+
}
30+
31+
/**
32+
* @param class-string<T> $model
33+
* @return T
34+
*/
35+
public function factory(string $model, ...$arguments)
36+
{
37+
$factory = $this->factory;
38+
39+
if (isset($arguments[1]) && is_string($arguments[1])) {
40+
return $factory->of($arguments[0], $arguments[1])->times($arguments[2] ?? null);
41+
}
42+
if (isset($arguments[1])) {
43+
return $factory->of($arguments[0])->times($arguments[1]);
44+
}
45+
46+
return $factory->of($arguments[0]);
47+
}
48+
49+
public function load(string $path): void
50+
{
51+
$this->factory->load($path);
52+
}
53+
}

src/TestCase.php

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,105 @@
1414
use Mockery as m;
1515
use Throwable;
1616

17+
use function Hyperf\Support\class_basename;
18+
use function Hyperf\Support\class_uses_recursive;
19+
1720
/**
1821
* @internal
1922
* @coversNothing
2023
*/
2124
abstract class TestCase extends \PHPUnit\Framework\TestCase
2225
{
2326
use Concerns\InteractsWithContainer;
27+
use Concerns\InteractsWithModelFactory;
2428
use Concerns\MakesHttpRequests;
2529
use Concerns\RunTestsInCoroutine;
2630

31+
/**
32+
* The callbacks that should be run after the application is created.
33+
*/
34+
protected array $afterApplicationCreatedCallbacks = [];
35+
36+
/**
37+
* The callbacks that should be run before the application is destroyed.
38+
*/
39+
protected array $beforeApplicationDestroyedCallbacks = [];
40+
41+
/**
42+
* The exception thrown while running an application destruction callback.
43+
*/
44+
protected ?Throwable $callbackException = null;
45+
2746
protected function setUp(): void
2847
{
2948
$this->refreshContainer();
49+
50+
$this->setUpTraits();
51+
52+
foreach ($this->afterApplicationCreatedCallbacks as $callback) {
53+
$callback();
54+
}
3055
}
3156

3257
protected function tearDown(): void
3358
{
3459
$this->flushContainer();
3560

61+
$this->callBeforeApplicationDestroyedCallbacks();
62+
3663
try {
3764
m::close();
38-
} catch (Throwable) {
65+
} catch (Throwable $e) {
66+
}
67+
68+
if ($this->callbackException) {
69+
throw $this->callbackException;
70+
}
71+
}
72+
73+
/**
74+
* Boot the testing helper traits.
75+
*
76+
* @return array
77+
*/
78+
protected function setUpTraits()
79+
{
80+
$uses = array_flip(class_uses_recursive(static::class));
81+
82+
foreach ($uses as $trait) {
83+
if (method_exists($this, $method = 'setUp' . class_basename($trait))) {
84+
$this->{$method}();
85+
}
86+
87+
if (method_exists($this, $method = 'tearDown' . class_basename($trait))) {
88+
$this->beforeApplicationDestroyed(fn () => $this->{$method}());
89+
}
90+
}
91+
92+
return $uses;
93+
}
94+
95+
/**
96+
* Register a callback to be run before the application is destroyed.
97+
*/
98+
protected function beforeApplicationDestroyed(callable $callback)
99+
{
100+
$this->beforeApplicationDestroyedCallbacks[] = $callback;
101+
}
102+
103+
/**
104+
* Execute the application's pre-destruction callbacks.
105+
*/
106+
protected function callBeforeApplicationDestroyedCallbacks()
107+
{
108+
foreach ($this->beforeApplicationDestroyedCallbacks as $callback) {
109+
try {
110+
$callback();
111+
} catch (Throwable $e) {
112+
if (! $this->callbackException) {
113+
$this->callbackException = $e;
114+
}
115+
}
39116
}
40117
}
41118
}

0 commit comments

Comments
 (0)