Skip to content

Commit

Permalink
v2.3
Browse files Browse the repository at this point in the history
  • Loading branch information
pabloelcolombiano committed Jun 9, 2021
2 parents d458fbf + 0abaa73 commit a87901c
Show file tree
Hide file tree
Showing 18 changed files with 526 additions and 9 deletions.
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,56 @@ You may continue using them along with the Fixture Factories, these will work ju

## [Creating Test Fixtures](docs/examples.md)

In this section, we'll see how to create test fixtures.
In this section, we will see how to create test fixtures.

#### Example:
Persisting five articles having each three different authors, each with different addresses, in different cities, but all located in Kenya:
```$xslt
$article = ArticleFactory::make(5)->with('Authors[3].Address.City.Country', ['name' => 'Kenya'])->persist();
```

#### On the command line:
Factories can also conveniently populate your database in order to test your application on the browser.
The following command will persist 5 articles, each with 3 irish authors, considering that the `ArticleFactory` class features
a `withThreeIrishAuthors()` method:
```$xslt
bin/cake fixture_factories_persist Authors -n 5 -m withThreeIrishAuthors
```
The option `--dry-run` or `-d` will display the output without persisting.
The option `-c` will persist in the connection provided (default is `test`).
The option `-w` will create associated fixtures.

The `fixture_factories_persist` command is featured on CakePHP 4 only (open to contribution for CakePHP 3).

#### Scenarios:

You can create scenarios that will persist a multitude of test fixtures. This can be useful to seed your
test database with a reusable set of data.

Use the `CakephpFixtureFactories\Scenario\ScenarioAwareTrait`
in your test and load your scenario with the `loadFixtureScenario()` method. You can either provide the
fully qualified name of the scenario class, or place your scenarios under the `App\Test\Scenario` namespace.

Scenarios should implement the `CakephpFixtureFactories\Scenario\FixtureScenarioInterface` class.
[This test](tests/TestCase/Scenario/FixtureScenarioTest.php) provides an example on how to use scenarios.

## Querying the database

Because the fixture factories are closely related to the database, the package provide two methods to conveniently
query the database. Note that both methods will by-pass the `beforeFind` event, facilitating the inspection of your
test database.

#### ArticleFactory::find()
This method will return a query on the table related to the given factory.

#### ArticleFactory::count()
This method will return the number of entries in the table of the given factory.

## [Test Lifecycle](docs/lifecycle.md)

The only step performed by the package's test suite is to truncate *dirty* tables before each test.
The only step performed by the package's test suite is to truncate *dirty* tables before each test. More documentation
on the management of the test database may be found
[in the cakephp test suite light documentation](https://github.com/vierge-noire/cakephp-test-suite-light).

## Authors
* Juan Pablo Ramirez
Expand Down
20 changes: 20 additions & 0 deletions src/Error/FixtureScenarioException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 1.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace CakephpFixtureFactories\Error;

use Cake\Core\Exception\Exception;

class FixtureScenarioException extends Exception
{
}
23 changes: 23 additions & 0 deletions src/Factory/BaseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Cake\Datasource\EntityInterface;
use Cake\I18n\I18n;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use CakephpFixtureFactories\Error\PersistenceException;
Expand Down Expand Up @@ -581,4 +582,26 @@ public function mergeAssociated(array $data)

return $this;
}

/**
* Query the factory's related table without before find.
*
* @param string $type the type of query to perform
* @param array $options An array that will be passed to Query::applyOptions()
* @return \Cake\ORM\Query The query builder
*/
public static function find(string $type = 'all', array $options = []): Query
{
return self::make()->getTable()->find($type, $options);
}

/**
* Count the factory's related table entries without before find.
*
* @return int
*/
public static function count(): int
{
return self::find()->count();
}
}
5 changes: 2 additions & 3 deletions src/Factory/DataCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public function getCompiledTemplateData()
* @param bool $setPrimaryKey Set the primary key if this entity is alone or the first of an array.
* @return \Cake\Datasource\EntityInterface
*/
public function compileEntity($injectedData, $setPrimaryKey = false): EntityInterface
public function compileEntity($injectedData = [], bool $setPrimaryKey = false): EntityInterface
{
if ($injectedData instanceof EntityInterface) {
$entity = $injectedData;
Expand Down Expand Up @@ -286,7 +286,6 @@ private function mergeWithAssociatedData(EntityInterface $entity): self
private function mergeWithToOne(EntityInterface $entity, string $associationName, array $data): void
{
$count = count($data);
$associationName = Inflector::singularize($associationName);
/** @var \CakephpFixtureFactories\Factory\BaseFactory $factory */
$factory = $data[$count - 1];

Expand Down Expand Up @@ -358,7 +357,7 @@ public function getMarshallerAssociationName(string $associationName): string
$result = [];
$cast = explode('.', $associationName);
$table = $this->getFactory()->getRootTableRegistry();
foreach ($cast as $i => $ass) {
foreach ($cast as $ass) {
$association = $table->getAssociation($ass);
$result[] = $association->getProperty();
$table = $association->getTarget();
Expand Down
15 changes: 13 additions & 2 deletions src/Factory/FactoryAwareTrait.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 2.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace CakephpFixtureFactories\Factory;

use Cake\Core\Configure;
Expand All @@ -15,7 +26,7 @@ trait FactoryAwareTrait
* Additionnal arguments are passed *as is* to `BaseFactory::make`
*
* @param string $name Factory or model name
* @param string|array[] ...$arguments Additionnal arguments for `BaseFactory::make`
* @param string|array[] ...$arguments Additional arguments for `BaseFactory::make`
* @return \CakephpFixtureFactories\Factory\BaseFactory
* @see CakephpFixtureFactories\Factory\BaseFactory::make
*/
Expand Down Expand Up @@ -75,7 +86,7 @@ public static function getFactoryNameFromModelName(string $modelName): string
*/
public function getFactoryNamespace(?string $plugin = null): string
{
if (Configure::read('TestFixtureNamespace')) {
if (Configure::check('TestFixtureNamespace')) {
return Configure::read('TestFixtureNamespace');
} else {
return (
Expand Down
25 changes: 25 additions & 0 deletions src/Scenario/FixtureScenarioInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 2.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace CakephpFixtureFactories\Scenario;

interface FixtureScenarioInterface
{
/**
* Create your bunch of test fixtures in this method.
*
* @return void
*/
public function load();
}
49 changes: 49 additions & 0 deletions src/Scenario/ScenarioAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 2.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

namespace CakephpFixtureFactories\Scenario;

use CakephpFixtureFactories\Error\FixtureScenarioException;
use CakephpFixtureFactories\Factory\FactoryAwareTrait;

trait ScenarioAwareTrait
{
use FactoryAwareTrait;

/**
* Load a given fixture scenario
*
* @param string $scenario Name of the scenario or fully qualified class.
* @return void
*/
public function loadFixtureScenario(string $scenario): void
{
if (!class_exists($scenario)) {
// phpcs:disable
@[$scenarioName, $plugin] = array_reverse(explode('.', $scenario));
// phpcs:enable
$scenarioNamespace = trim($this->getFactoryNamespace($plugin), 'Factory') . 'Scenario';
$scenario = $scenarioNamespace . '\\' . $scenarioName . 'Scenario';
}

if (!is_subclass_of($scenario, FixtureScenarioInterface::class)) {
$msg = "The class {$scenario} must implement " . FixtureScenarioInterface::class;
throw new FixtureScenarioException($msg);
}

/** @var \CakephpFixtureFactories\Scenario\FixtureScenarioInterface $scenario */
$scenario = new $scenario();
$scenario->load();
}
}
10 changes: 10 additions & 0 deletions tests/Factory/ArticleFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,14 @@ public function withHiddenBiography(string $text)
Article::HIDDEN_PARAGRAPH_PROPERTY_NAME => $text
]);
}

public function published()
{
return $this->patchData(['published' => true]);
}

public function unpublished()
{
return $this->patchData(['published' => false]);
}
}
45 changes: 45 additions & 0 deletions tests/Factory/ArticlesAuthorFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 1.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace CakephpFixtureFactories\Test\Factory;

use CakephpFixtureFactories\Factory\BaseFactory;
use Faker\Generator;

class ArticlesAuthorFactory extends BaseFactory
{
/**
* Defines the Table Registry used to generate entities with
*
* @return string
*/
protected function getRootTableRegistryName(): string
{
return 'ArticlesAuthors';
}

/**
* Defines the default values of you factory. Useful for
* not nullable fields.
* Use the patchData method to set the field values.
* You may use methods of the factory here
*
* @return void
*/
protected function setDefaultTemplate(): void
{
$this->setDefaultData(function (Generator $faker) {
return [];
});
}
}
5 changes: 5 additions & 0 deletions tests/Factory/AuthorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ public function withAddress($parameter = null)
{
return $this->with('Address', AddressFactory::make($parameter));
}

public function fromCountry(string $name)
{
return $this->with('Address.City.Country', CountryFactory::make(compact('name')));
}
}
30 changes: 30 additions & 0 deletions tests/Scenario/FiveAustralianAuthorsScenario.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 2.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace CakephpFixtureFactories\Test\Scenario;


use CakephpFixtureFactories\Scenario\FixtureScenarioInterface;
use CakephpFixtureFactories\Test\Factory\AuthorFactory;

class FiveAustralianAuthorsScenario implements FixtureScenarioInterface
{
const COUNTRY_NAME = 'Australia';

const N = 5;

public function load()
{
AuthorFactory::make(self::N)->fromCountry(self::COUNTRY_NAME)->persist();
}
}
28 changes: 28 additions & 0 deletions tests/Scenario/TenAustralianAuthorsScenario.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);

/**
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) 2020 Juan Pablo Ramirez and Nicolas Masson
* @link https://webrider.de/
* @since 2.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace CakephpFixtureFactories\Test\Scenario;

use CakephpFixtureFactories\Scenario\FixtureScenarioInterface;
use CakephpFixtureFactories\Scenario\ScenarioAwareTrait;

class TenAustralianAuthorsScenario implements FixtureScenarioInterface
{
use ScenarioAwareTrait;

public function load()
{
$this->loadFixtureScenario(FiveAustralianAuthorsScenario::class);
$this->loadFixtureScenario(FiveAustralianAuthorsScenario::class);
}
}
Loading

0 comments on commit a87901c

Please sign in to comment.