久々に思いついたモジュールを作ってみました。テスト用のデータを入れるために役に立つ(と思う)モジュールです。
Repository
https://github.com/shibayu36/p5-DBIx-DataFactoryに置いてあります。
またPrepanにも上げました。レビューお願いします。http://prepan.org/module/3Yz7PYrBzi
Synopsis
大体下のような感じに使います。
# schema CREATE TABLE test_factory ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `int` int, `string` varchar(255), `text` text DEFAULT NULL, PRIMARY KEY (id) ) DEFAULT CHARSET=binary; # in your t/*.t use Test::Factory::DBI; Test::Factory::DBI->username('nobody'); Test::Factory::DBI->password('nobody'); Test::Factory::DBI->create_factory_method( method => 'create_factory_data', dbi => 'dbi:mysql:dbname=test_factory;host=localhost', table => 'test_factory', columns => { int => { type => 'Int', size => 10, }, string => { type => 'Str', size => 10, }, }, ); my $values = create_factory_data( text => 'test text', ); # will insert followed data +----+------------+--------+------------+ | id | int | double | string | +----+------------+--------+------------+ | 1 | 1336609917 | NULL | ALdGTwmEl3 | +----+------------+--------+------------+
Description
テスト用にデータベースにデータを入れるとき、皆さんならどうしてますか?
よく使われているのはFixtureだと思うのですが、これだとデータを追加したときに他のテストが通らなくなったり、結構複雑にテストをしたいときに、いちいちデータを作るのがめんどくさいです。なので僕は最近は使わなくなりました。
そのかわり、例えばテスト用のデータを生成するようなメソッドを予め作っておいて、テストを書くときにはそのメソッドを使ってデータを入れてました。例えば下のような感じです。
sub create_user (%) { my (%args) = @_; require String::Random; require Sample::User; # 例えばこれがO/Rマッパーだとする。 my $user = Sample::User->create( user_id => $args{user_id} || int(rand(100000)), user_type => $args{user_type} || 0, ); if ($args{country}) { $user->country($args{country}); } if ($args{lang}) { $user->lang($args{lang}); } unless ($args{description}) { $args{description} = String::Random->new->randregex('[a-zA-Z0-9]{10}'); } $user->description($args{description}); return $user; }
上のようなメソッドを作るとテストの時も結構簡単にデータを作れるので、最近はこういうふうにしてました。ただ、これだとテーブルごとに毎回メソッドを作るのが大変だったり、columnを増やすたびに、毎回手を入れないといけなかったので、面倒になって来ました。
そのため、このようなメソッドを作るのを簡単にするようなモジュールを作りました。上の例だと、下のように書けます。
use Test::Factory::DBI; Test::Factory::DBI->username('nobody'); Test::Factory::DBI->password('nobody'); Test::Factory::DBI->create_factory_method( method => 'create_user', dbi => 'dbi:mysql:dbname=user_test;host=localhost', table => 'user_test', columns => { user_id => { type => 'Int', size => 5, }, user_type => sub { 0 }, description => { type => 'Str', size => 10, }, }, ); my $values = create_user( user_type => 2, country => 'jp', lang => 'ja', );
Typeの拡張
また、一応columnsで指定するTypeを拡張できるように作りました。例えば、「あるセットの中からどれかrandomで選んで挿入したい」みたいな要求があったときは、以下のようなクラスを作ります。
package Test::Factory::DBI::Type::Set; use strict; use warnings; use Carp; use base qw(Test::Factory::DBI::Type); use Smart::Args; sub type_name { 'Set' } sub make_value { args my $class => 'ClassName', my $set => 'ArrayRef'; return $set->[int rand(scalar @$set)]; } 1;
その後、Test::Factory::DBIにこのTypeを登録したら、使えます。
use Test::Factory::DBI; Test::Factory::DBI->add_type('Test::Factory::DBI::Type::Set'); Test::Factory::DBI->username('nobody'); Test::Factory::DBI->password('nobody'); Test::Factory::DBI->create_factory_method( method => 'create_user', dbi => 'dbi:mysql:dbname=user_test;host=localhost', table => 'user_test', columns => { user_id => { type => 'Int', size => 5, }, user_type => sub { 0 }, description => { type => 'Str', size => 10, }, lang => { type => 'Set', set => ['ja', 'en'], }, }, ); my $values = create_user();
追記
Test::Factory::DBIっていう名前はやめたほうが良いということでDBIx::DataFactoryって名前にしようかなと考えています。repositoryも変わりました。
https://github.com/shibayu36/p5-DBIx-DataFactory
まとめ
という訳で、こんな感じのモジュールを作って見ました。何か指摘があれば@shiba_yu36か、prepanにでも言ってもらえるとありがたいです。