Adds ModelFactory support for hyperf/testing (#5894)

This commit is contained in:
Deeka Wong 2023-07-01 20:25:51 +08:00 committed by GitHub
parent defa69f36c
commit 030405b092
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 180 additions and 1 deletions

View File

@ -24,6 +24,7 @@
- [#5815](https://github.com/hyperf/hyperf/pull/5815) Added alias as `mysql` for `pdo` in `hyperf/db`.
- [#5849](https://github.com/hyperf/hyperf/pull/5849) Support for insert update and select using enums.
- [#5855](https://github.com/hyperf/hyperf/pull/5855) Added `hyperf/closure-command` component.
- [#5894](https://github.com/hyperf/hyperf/pull/5894) Added `model-factory` support for `hyperf/testing`.
## Optimized

View File

@ -35,6 +35,7 @@
"doctrine/instantiator": "^1.0",
"egulias/email-validator": "^3.0",
"elasticsearch/elasticsearch": "^7.0",
"fakerphp/faker": "^1.23",
"fig/http-message-util": "^1.1.2",
"filp/whoops": "^2.7",
"friendsofphp/php-cs-fixer": "~3.16.0",

View File

@ -32,6 +32,9 @@
"hyperf/utils": "~3.1.0",
"symfony/http-foundation": "^5.4|^6.0"
},
"suggest": {
"fakerphp/faker": "Required to use Faker feature.(^1.23)"
},
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Testing\Concerns;
use Faker\Factory as FakerFactory;
use Hyperf\Testing\ModelFactory;
trait InteractsWithModelFactory
{
protected ?ModelFactory $modelFactory = null;
protected string|array $factoryPath = BASE_PATH . '/database/factories';
protected function setUpInteractsWithModelFactory()
{
if (! class_exists(FakerFactory::class)) {
return;
}
$this->modelFactory = ModelFactory::create(
FakerFactory::create('en_US')
);
foreach ((array) $this->factoryPath as $path) {
if (is_dir($path)) {
$this->modelFactory->load($path);
}
}
}
protected function tearDownInteractsWithModelFactory()
{
$this->modelFactory = null;
}
}

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Testing;
use Faker\Generator;
use Hyperf\Database\Model\Factory;
/**
* @template T
*/
class ModelFactory
{
public function __construct(protected Factory $factory)
{
}
public static function create(Generator $faker)
{
return new static(new Factory($faker));
}
/**
* @param class-string<T> $model
* @return T
*/
public function factory(string $model, ...$arguments)
{
$factory = $this->factory;
if (isset($arguments[1]) && is_string($arguments[1])) {
return $factory->of($arguments[0], $arguments[1])->times($arguments[2] ?? null);
}
if (isset($arguments[1])) {
return $factory->of($arguments[0])->times($arguments[1]);
}
return $factory->of($arguments[0]);
}
public function load(string $path): void
{
$this->factory->load($path);
}
}

View File

@ -14,6 +14,9 @@ namespace Hyperf\Testing;
use Mockery as m;
use Throwable;
use function Hyperf\Support\class_basename;
use function Hyperf\Support\class_uses_recursive;
/**
* @internal
* @coversNothing
@ -21,21 +24,95 @@ use Throwable;
abstract class TestCase extends \PHPUnit\Framework\TestCase
{
use Concerns\InteractsWithContainer;
use Concerns\InteractsWithModelFactory;
use Concerns\MakesHttpRequests;
use Concerns\RunTestsInCoroutine;
/**
* The callbacks that should be run after the application is created.
*/
protected array $afterApplicationCreatedCallbacks = [];
/**
* The callbacks that should be run before the application is destroyed.
*/
protected array $beforeApplicationDestroyedCallbacks = [];
/**
* The exception thrown while running an application destruction callback.
*/
protected ?Throwable $callbackException = null;
protected function setUp(): void
{
$this->refreshContainer();
$this->setUpTraits();
foreach ($this->afterApplicationCreatedCallbacks as $callback) {
$callback();
}
}
protected function tearDown(): void
{
$this->flushContainer();
$this->callBeforeApplicationDestroyedCallbacks();
try {
m::close();
} catch (Throwable) {
} catch (Throwable $e) {
}
if ($this->callbackException) {
throw $this->callbackException;
}
}
/**
* Boot the testing helper traits.
*
* @return array
*/
protected function setUpTraits()
{
$uses = array_flip(class_uses_recursive(static::class));
foreach ($uses as $trait) {
if (method_exists($this, $method = 'setUp' . class_basename($trait))) {
$this->{$method}();
}
if (method_exists($this, $method = 'tearDown' . class_basename($trait))) {
$this->beforeApplicationDestroyed(fn () => $this->{$method}());
}
}
return $uses;
}
/**
* Register a callback to be run before the application is destroyed.
*/
protected function beforeApplicationDestroyed(callable $callback)
{
$this->beforeApplicationDestroyedCallbacks[] = $callback;
}
/**
* Execute the application's pre-destruction callbacks.
*/
protected function callBeforeApplicationDestroyedCallbacks()
{
foreach ($this->beforeApplicationDestroyedCallbacks as $callback) {
try {
$callback();
} catch (Throwable $e) {
if (! $this->callbackException) {
$this->callbackException = $e;
}
}
}
}
}