Mais conteúdo relacionado Semelhante a Phactory (20) Phactory1. A Database Factory for PHP
http://phactory.org
Chris Kite
Sr. Web Engineer at Offers.com
© 2009 Vertive, Inc.
Proprietary and Confidential @chriskite
2. Phactory: What is it?
Alternative to database fixtures for unit
tests
Define and create objects in code
Provides a lightweight ORM
Works with MySQL, SQLite, and
MongoDB
© 2009 Vertive, Inc.
Proprietary and Confidential
5. Database Fixtures
A fixture is a statically defined set of data
Each test can have its own dataset
PHPUnit provides support for loading
fixtures:
class DatabaseTest extends PHPUnit_Extensions_Database_TestCase
{
protected function getConnection()
{
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', '');
return $this->createDefaultDBConnection($pdo, 'testdb');
}
protected function getDataSet()
{
return $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-seed.xml');
}
}
© 2009 Vertive, Inc.
Proprietary and Confidential
6. Database Fixtures
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<post
post_id="1"
title="My First Post"
date_created="2008-12-01 12:30:29"
contents="This is my first post" rating="5"
/>
<post
post_id="2"
title="My Second Post"
date_created="2008-12-04 15:35:25"
contents="This is my second post"
/>
</dataset> Vertive, Inc.
© 2009
Proprietary and Confidential Example from http://www.phpunit.de/manual/current/en/database.html
7. Database Fixtures
Drawbacks:
» Typically in an unfriendly format like XML
» You are left to your own devices to retrieve
and manipulate data in your test
» Can’t dynamically create objects
» No concept of associations
© 2009 Vertive, Inc.
Proprietary and Confidential
8. Database Factories
Define database test data in code, not flat
files
Create objects dynamically, rather than
loading them all at once
Define associations between objects
Can integrate with or provide ORM
functionality
© 2009 Vertive, Inc.
Proprietary and Confidential
9. Database Factories
Phactory Example
<?
Phactory::setConnection(new PDO('sqlite:test.db'));
Phactory::define('user', array('name' => 'Test User',
'email' => 'user@example.com'));
$user = Phactory::create('user'); // creates a row in the 'users' table
print("Hello, {$user->name}!"); // prints "Hello, Test User!"
© 2009 Vertive, Inc.
Proprietary and Confidential
11. Connecting to the Database
Phactory supports MySQL, SQLite, and
MongoDB
Uses PDO for SQL databases
<?
require_once 'Phactory/lib/Phactory.php';
$pdo = new PDO('mysql:host=127.0.0.1; dbname=testdb', 'user', 'password');
Phactory::setConnection($pdo);
© 2009 Vertive, Inc.
Proprietary and Confidential
12. Defining Table Blueprints
A blueprint defines default values for
objects created in a particular table
<?
Phactory::define('user', array('name' => 'test_user',
'age' => 20));
Phactory::define('post', array('text' => 'This is a post',
'created_at' => 1296663323));
© 2009 Vertive, Inc.
Proprietary and Confidential
13. Creating Objects
When creating an object with Phactory,
you can:
» Specify values for fields that weren’t in the
blueprint definition
» Override any of the default values
» Associate with other objects
© 2009 Vertive, Inc.
Proprietary and Confidential
14. Creating Objects
Phactory::define('user', array('name' => 'test_user', 'age' => 20));
$john = Phactory::create('user', array('name' => 'John Doe'));
$joe = Phactory::create('user', array('name' => 'Joe Smith', 'activated' => 1));
$anon = Phactory::create('user');
// $john looks like this:
$john->id == 1;
$john->name == 'John Doe';
$john->activated == 0;
// $joe looks like this:
$joe->id == 2;
$joe->name == 'Joe Smith';
$joe->activated == 1;
// $anon looks like this:
$anon->id == 3;
$anon->name == 'test_user';
$anon->activated == 0;
© 2009 Vertive, Inc.
Proprietary and Confidential
15. Retrieving Objects
Basic ORM functionality allows you to
retrieve Phactory objects from the
database
Uses a simple get() method which takes
an array of columns to match
$joe = Phactory::get('user', array('id' => 2));
$joe = Phactory::get('user', array('age' => 20, 'activated' => 1));
© 2009 Vertive, Inc.
Proprietary and Confidential
16. Associations
For SQL databases, Phactory provides
many-to-one and many-to-many
associations
Foreign key columns and join tables are
filled in automatically when creating an
object with associations
© 2009 Vertive, Inc.
Proprietary and Confidential
17. Associations
Phactory::define('author');
Phactory::define('book',
array('name' => 'Test Book'),
array('primary_author' => Phactory::manyToOne('author')));
$twain = Phactory::create('author', array('name' => 'Mark Twain'));
$book = Phactory::createWithAssociations('book', array('primary_author'
=> $twain));
$book->author_id == $twain->getId();
© 2009 Vertive, Inc.
Proprietary and Confidential
18. Sequences
Define blueprints with automatically
incrementing values
» Include ‘$n’ in the definition
» Sequence starts at 0, and is incremented
each time an object is created
Phactory::define('user', array('name' => 'user$n', 'age' => '$n'));
$user0 = Phactory::create('user'); // name == 'user0', age == '0'
$user1 = Phactory::create('user'); // name == 'user1', age == '1'
$user2 = Phactory::create('user'); // name == 'user2', age == '2'
© 2009 Vertive, Inc.
Proprietary and Confidential
20. Basic Test Setup
require_once 'Phactory/lib/Phactory.php';
class ExampleTest extends PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
// create a db connection and tell Phactory to use it
$pdo = new PDO("sqlite:test.db");
Phactory::setConnection($pdo);
// reset any existing blueprints and empty any tables Phactory has used
Phactory::reset();
// define default values for each user we will create
Phactory::define('user', array('name' => 'Test User $n', 'age' => 18));
}
public static function tearDownAfterClass()
{
Phactory::reset();
}
public function tearDown()
{
// delete all objects from defined tables, but do not erase blueprints
Phactory::recall();
}
© 2009 Vertive, Inc.
Proprietary and Confidential
21. Structuring Shared Definitions
Usually many of the test classes in your
suite will need to use the same tables
Define blueprints in one place, share them
among many tests
» Can include() a file of definitions, put
definitions in a static class, etc.
© 2009 Vertive, Inc.
Proprietary and Confidential
22. Structuring Shared Definitions
SharedDefinitions.php
<?
Phactory::define('tag', array('name' => 'Tag $n'));
Phactory::define('post',
array('name' => 'Test Blog Post', 'content' => 'Test Content'),
array('tag' => Phactory::manyToMany('tag', 'posts_tags')));
ExampleTest.php
class ExampleTest extends PHPUnit_Framework_TestCase
{
public static function setUpBeforeClass()
{
$pdo = new PDO("sqlite:test.db");
Phactory::setConnection($pdo);
Phactory::reset();
// include definitions common to several tests
include('SharedDefinitions.php');
}
}
© 2009 Vertive, Inc.
Proprietary and Confidential
23. Dynamic Objects
Recall that with fixtures, your test data is
all loaded at the start of the test
With Phactory, you can create or change
test data during a test
© 2009 Vertive, Inc.
Proprietary and Confidential
24. Dynamic Objects
class MyPostClass {
public static function countTagsForPost($post_id) {
$stmt = $pdo->prepare("SELECT COUNT(*) AS num_tags
FROM `posts_tags` WHERE `post_id` = ?");
$stmt->execute(array($post_id));
$result = $stmt->fetch();
return $result['num_tags'];
}
}
Phactory::define('tag',
array('name' => 'Tag $n'),
array('post' => Phactory::manyToMany('post', 'posts_tags')));
Phactory::define('post',
array('name' => 'Test Blog Post', 'content' => 'Test Content'),
array('tag' => Phactory::manyToMany('tag', 'posts_tags')));
$post = Phactory::create('post');
$this->assertEquals(0, MyPostClass::countTagsForPost($post->getId()));
$tag = Phactory::createWithAssociations('tag', array('post' => $post));
© 2009 Vertive, Inc.
$this->assertEquals(1, MyPostClass::countTagsForPost($post->getId()));
Proprietary and Confidential
25. Using Phactory with MongoDB
require_once 'Phactory/lib/PhactoryMongo.php';
Uses the Mongo PHP driver
Almost exactly the same as regular SQL
Phactory, except:
» Documents returned as arrays rather than
Phactory_Row objects
» Phactory::get() supports all Mongo queries
» Associations: embedsOne and embedsMany
http://phactory.org/mongodb-guide/
© 2009 Vertive, Inc.
Proprietary and Confidential
26. QUESTIONS
© 2009 Vertive, Inc.
Proprietary and Confidential
27. Thank You!
These slides are online at
http://bit.ly/PhactoryWebinar
Contact me on Twitter: @chriskite
Visit http://phactory.org to download and
for more information
© 2009 Vertive, Inc.
Proprietary and Confidential