Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fabricator counts #3213

Merged
merged 1 commit into from
Jul 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions system/Test/CIDatabaseTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ protected function setUp(): void
$this->migrations->latest('tests');
}
}

// Reset counts on faked items
Fabricator::resetCounts();
}

if (! empty($this->seed))
Expand Down
73 changes: 64 additions & 9 deletions system/Test/Fabricator.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
*/
class Fabricator
{
/**
* Array of counts for fabricated items
*
* @var array
*/
protected static $tableCounts = [];

/**
* Locale-specific Faker instance
*
Expand Down Expand Up @@ -152,20 +159,64 @@ public function __construct($model, array $formatters = null, string $locale = n
$this->setFormatters($formatters);
}

//--------------------------------------------------------------------

/**
* Reset internal counts
*/
public static function resetCounts()
{
self::$tableCounts = [];
}

/**
* Reset state to defaults
* Get the count for a specific table
*
* @return $this
* @param string $table Name of the target table
*
* @return integer
*/
public static function getCount(string $table): int
{
return empty(self::$tableCounts[$table]) ? 0 : self::$tableCounts[$table];
}

/**
* Set the count for a specific table
*
* @param string $table Name of the target table
* @param integer $count Count value
*
* @return integer The new count value
*/
public function reset(): self
public static function setCount(string $table, int $count): int
{
$this->setFormatters();
self::$tableCounts[$table] = $count;
return $count;
}

$this->overrides = $this->tempOverrides = [];
$this->locale = config('App')->defaultLocale;
$this->faker = Factory::create($this->locale);
/**
* Increment the count for a table
*
* @param string $table Name of the target table
*
* @return integer The new count value
*/
public static function upCount(string $table): int
{
return self::setCount($table, self::getCount($table) + 1);
}

return $this;
/**
* Decrement the count for a table
*
* @param string $table Name of the target table
*
* @return integer The new count value
*/
public static function downCount(string $table): int
{
return self::setCount($table, self::getCount($table) - 1);
}

//--------------------------------------------------------------------
Expand Down Expand Up @@ -515,7 +566,11 @@ public function create(int $count = null, bool $mock = false)
// Iterate over new entities and insert each one, storing insert IDs
foreach ($this->make($count ?? 1) as $result)
{
$ids[] = $this->model->insert($result, true);
if ($id = $this->model->insert($result, true))
{
$ids[] = $id;
self::upCount($this->model->table);
}
}

// If the model defines a "withDeleted" method for handling soft deletes then use it
Expand Down
21 changes: 21 additions & 0 deletions tests/system/Database/Live/FabricatorLiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,25 @@ public function testHelperCreates()

$this->seeInDatabase('user', ['name' => $result->name]);
}

public function testCreateIncrementsCount()
{
$fabricator = new Fabricator(UserModel::class);
$fabricator->setOverrides(['country' => 'China']);

$count = Fabricator::getCount('user');

$fabricator->create();

$this->assertEquals($count + 1, Fabricator::getCount('user'));
}

public function testHelperIncrementsCount()
{
$count = Fabricator::getCount('user');

fake(UserModel::class, ['country' => 'Italy']);

$this->assertEquals($count + 1, Fabricator::getCount('user'));
}
}
85 changes: 85 additions & 0 deletions tests/system/Test/FabricatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ class FabricatorTest extends CIUnitTestCase
'deleted_at' => 'date',
];

protected function tearDown(): void
{
parent::tearDown();

Fabricator::resetCounts();
}

//--------------------------------------------------------------------

public function testConstructorWithString()
Expand Down Expand Up @@ -398,4 +405,82 @@ public function testCreateMockSetsDatabaseFields()
$this->assertObjectHasAttribute('deleted_at', $result);
$this->assertNull($result->deleted_at);
}

//--------------------------------------------------------------------

public function testSetCountReturnsCount()
{
$result = Fabricator::setCount('goblins', 42);

$this->assertEquals(42, $result);
}

public function testSetCountSetsValue()
{
Fabricator::setCount('trolls', 3);
$result = Fabricator::getCount('trolls');

$this->assertEquals(3, $result);
}

public function testGetCountNewTableReturnsZero()
{
$result = Fabricator::getCount('gremlins');

$this->assertEquals(0, $result);
}

public function testUpCountIncrementsValue()
{
Fabricator::setCount('orcs', 12);
Fabricator::upCount('orcs');

$this->assertEquals(13, Fabricator::getCount('orcs'));
}

public function testUpCountReturnsValue()
{
Fabricator::setCount('hobgoblins', 12);
$result = Fabricator::upCount('hobgoblins');

$this->assertEquals(13, $result);
}

public function testUpCountNewTableReturnsOne()
{
$result = Fabricator::upCount('ogres');

$this->assertEquals(1, $result);
}

public function testDownCountDecrementsValue()
{
Fabricator::setCount('orcs', 12);
Fabricator::downCount('orcs');

$this->assertEquals(11, Fabricator::getCount('orcs'));
}

public function testDownCountReturnsValue()
{
Fabricator::setCount('hobgoblins', 12);
$result = Fabricator::downCount('hobgoblins');

$this->assertEquals(11, $result);
}

public function testDownCountNewTableReturnsNegativeOne()
{
$result = Fabricator::downCount('ogres');

$this->assertEquals(-1, $result);
}

public function testResetClearsValue()
{
Fabricator::setCount('giants', 1000);
Fabricator::resetCounts();

$this->assertEquals(0, Fabricator::getCount('giants'));
}
}
55 changes: 55 additions & 0 deletions user_guide_src/source/testing/fabricator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,58 @@ This is equivalent to::
$fabricator = new Fabricator('App\Models\UserModel');
$fabricator->setOverrides(['name' => 'Gerry']);
$user = $fabricator->create();

Table Counts
============

Frequently your faked data will depend on other faked data. ``Fabricator`` provides a static
count of the number of faked items you have created for each table. Consider the following
example:

Your project has users and groups. In your test case you want to create various scenarios
with groups of different sizes, so you use ``Fabricator`` to create a bunch of groups.
Now you want to create fake users but don't want to assign them to a non-existant group ID.
Your model's fake method could look like this::

class UserModel
{
protected $table = 'users';

public function fake(Generator &$faker)
{
return [
'first' => $faker->firstName,
'email' => $faker->email,
'group_id' => rand(1, Fabricator::getCount('users')),
];
}

Now creating a new user will ensure it is a part of a valid group: ``$user = fake(UserModel::class);``

``Fabricator`` handles the counts internally but you can also access these static methods
to assist with using them:

**getCount(string $table): int**

Return the current value for a specific table (default: 0).

**setCount(string $table, int $count): int**

Set the value for a specific table manually, for example if you create some test items
without using a fabricator that you still wanted factored into the final counts.

**upCount(string $table): int**

Increment the value for a specific table by one and return the new value. (This is what is
used internally with ``Fabricator::create()``).

**downCount(string $table): int**

Decrement the value for a specific table by one and return the new value, for example if
you deleted a fake item but wanted to track the change.

**resetCounts()**

Resets all counts. Good idea to call this between test cases (though using
``CIDatabaseTestCase::$refresh = true`` does it automatically).