QuickBrownFox
, (*1)
ORM independent RDB fixture data generator., (*2)
Basic Usage
At first, define a session manager in your DI container or service locator:, (*3)
use Lapaz\QuickBrownFox\SessionManagerInterface;
use Lapaz\QuickBrownFox\EasySessionManager;
// $container points some application scope service locator
$container->set(SessionManagerInterface::class, function() use ($container) {
return new EasySessionManager($container->get('dbal.connection'));
// or return new EasySessionManager([/*DBAL connection parameters*/]);
});
Prepare new test session in your test case:, (*4)
use PHPUnit\Framework\TestCase;
use Lapaz\QuickBrownFox\SessionManagerInterface;
class BookRepositoryTest extends TestCase
{
protected $session;
protected function setUp()
{
/** @var ContainerInterface $container */
$this->session = $container->get(SessionManagerInterface::class)->newSession();
}
}
Session indicates single testing context. Database tables are automatically cleaned up in each sessions.
tearDown
method is not necessary. So, you can see the last state of database after test., (*5)
generate
Test your repository using randomly generated data by generate
method:, (*6)
public function testFindBook()
{
$this->session->into('books')->generate(10);
$books = (new BookRepository($this->connection))->findAll();
$this->assertCount(10, $books);
$this->assertNotNull($books[0]->getAuthor());
}
In above example, generate
method generates 10 random books. You don't need to care column definition.
QuickBrownFox automatically fills non-null columns with random values., (*7)
Also you don't need to care relative tables because foreign key constraints are resolved automatically.
If depending table is not filled yet, QuickBrownFox generates data for it., (*8)
load
You can test with detailed data using load
method:, (*9)
public function testGetBook()
{
$this->session->into('books')->load([
['id' => 1, 'title' => 'Design Pattern'],
['id' => 2, 'title' => 'Refactoring'],
]);
$repository = new BookRepository($this->connection);
$this->assertEquals('Design Pattern', $repository->get(1)->getTitle());
$this->assertEquals('Refactoring', $repository->get(2)->getTitle());
$this->assertNull($repository->get(3));
}
In this case, load
method loads specific data. If you don't specify some columns or relationships,
QuickBrownFox fills them with random values., (*10)
with
You can specify automatically filled value patterns using with
method:, (*11)
public function testFindBook()
{
$this->session->into('books')->with(function($i) {
return [
'title' => 'Design Pattern ' . ($i + 1),
'code' => sprintf('000-000-%03d', $i),
];
})->generate(10);
// test code here
}
public function testGetBook()
{
$this->session->into('books')->with([
'preferred' => true,
'rating' => function($i) { return 80 + $i * 5; },
])->load([
['id' => 1, 'title' => 'Design Pattern'],
['id' => 2, 'title' => 'Refactoring'],
]);
// test code here
}
with
method sets common attributes for each data by callable which returns array.
You can also use an array which has callable or constant values., (*12)
Advanced Usage
Predefined Fixtures and Generators
QuickBrownFox supports predefined fixtures and generators., (*13)
use Lapaz\QuickBrownFox\SessionManagerInterface;
use Lapaz\QuickBrownFox\FixtureManager;
// $container points some application scope service locator
$container->set(SessionManagerInterface::class, function() use ($container) {
$fixtures = new FixtureManager();
$fixtures->table('authors', function ($td) {
$td->fixture('GoF')->define([
['id' => 1, 'name' => "Erich Gamma"],
['id' => 2, 'name' => "Richard Helm"],
['id' => 3, 'name' => "Ralph Johnson"],
['id' => 4, 'name' => "John Vlissides"],
]);
});
$fixtures->table('books', function ($td) {
$td->generator('DesignPattern-N')->define(function($i) {
return [
'title' => 'Design Pattern ' . ($i + 1),
'code' => sprintf('000-000-%03d', $i),
'author_id' => 1,
];
});
});
return $fixtures->createSessionManager($container->get('dbal.connection'));
// or return $fixtures->createSessionManager([/*DBAL connection parameters*/]);
});
You can use named fixtures and generators in your test:, (*14)
public function testFindBook()
{
// Loads 4 gangs.
$this->session->into('authors')->load('GoF');
// Bind 8 books to 4 gangs as authors.
$this->session->into('books')->with('DesignPattern-N')->with([
'author_id' => function($i) { return $i % 4 + 1; },
])->generate(8);
$books = (new BookRepository($this->connection))->findAll();
$this->assertEquals("Design Pattern 1", $book[0]->getTitle());
$this->assertEquals("Erich Gamma", $book[0]->getAuthor()->getName());
$this->assertEquals("Design Pattern 8", $book[7]->getTitle());
$this->assertEquals("John Vlissides", $book[7]->getAuthor()->getName());
}
-
load
method can load predefined fixture by name.
-
with
method can set predefined generator by name.
It's useful when you have some common data structure in your application., (*15)
You can use with
method multiple times. They are merged., (*16)
Default Values
FixtureManager provides defaults
method to customize random value generation.
It's useful when table has some semantic constraints as its schema definition., (*17)
$fixtures->table('books', function ($td) {
$td->defaults([
'type' => function() {
return mt_rand(1, 3); // books.type must be 1, 2 or 3
}
]);
});
In above example, type
column is filled with random value between 1 and 3 even if not specified by with
., (*18)