Easier Database Fixtures
I recently posted about DBIx::Class::EasyFixture and I was shocked to receive an email from someone explaining how he uses it in production with Test::Class::Moose. Basically, the ability to write this was the killer feature for him:
sub test_teardown {
my $test = shift;
$test->fixtures->unload;
}
As happy as I am with how easy it is to create and manage database fixtures with DBix::Class::EasyFixture
, when I was writing the slides for my Perl testing class, I found that I wanted the fixtures to be even easier (I should call this TDD: Training Driven Development). Previously, if you wanted to create a fixture for a Person
and that was automatically linked to an associated Customer
class, you would do something like this:
person_bob => {
new => 'Person',
using => {
name => 'Bob',
birthday => DateTime->new( ... ),
},
next => [qw/customer_bob/],
},
customer_bob => {
new => 'Customer',
using => {
first_purchase => DateTime->new( ... ),
},
requires => {
person_bob => {
our => 'person_id',
their => 'person_id',
},
},
That was still too verbose for me, so now I support this syntax:
person_bob => {
new => 'Person',
using => {
name => 'Bob',
birthday => DateTime->new( ... ),
},
next => [qw/customer_bob/],
},
customer_bob => {
new => 'Customer',
using => {
first_purchase => DateTime->new( ... ),
person_id => { person_bob => 'person_id' },
},
},
However, since both Customer
and Person
have the same field name for person_id
in our example, you can just take a reference to person_bob
:
customer_bob => {
new => 'Customer',
using => {
first_purchase => DateTime->new( ... ),
person_id => \'person_bob',
},
},
So now it's much easier to write fixtures.
It's now also easier to use fixtures because the load()
method now returns the fixtures it's loaded:
my $schema = My::Schema->connect( ... );
my $fixtures = My::Fixtures->new({ schema => $schema });
my $customer = $schema->load('customer_bob');
my @customers = $schema->load('all_customers');
Called in scalar context, load()
always returns the first fixture loaded. In list context, it returns all fixtures loaded in the order they were loaded. Note that this means "requested" fixtures. When you call $schema->load('customer_bob')
, it knows to load the person_bob
fixture, but that is done internally and not returned via the load()
statement. Thus, if person_bob
has a next
entry causing it to load customer_bob
, the following two lines load the same information, but the first will return a Person
object and the second will return a Customer
object:
my $person = $fixture->load('person_bob');
# versus
my $customer = $fixture->load('customer_bob');
And for the second, you can still get the Person
object:
my $person = $fixture->get_result('person_bob');
Of course, you can still do things the hard way:
$fixture->load('person_bob');
my $person = $schema->resultset('Person')->find({email => $email});
Enjoy!
As always, if you're interested in hiring me or any of the talented developers we have working at All Around The World, drop me a line at ovid@allaroundtheworld.fr.
Leave a comment