この記事は、モバイルファクトリー Advent Calendar 2015 2日目の記事です
昨日は、nekobato さんの superagentとaxiosの使い分け でした
Perl Advent Calender 2014 の最高の記事の
ソースコード以外もとにかくテストする。もしくはカバレッジだけではダメだという話 から、
アプリケーション設定ファイルのテスト
と Fixtureのテスト
の例を書いてみたいと思います
アプリケーション設定ファイルのテスト
本番環境、開発環境、テスト環境で設定が過不足がないかチェックするため、 Test::Deep, Test::Deep::Matcher を利用しています
テストの流れとしては
- 本番環境の設定値を、Test::Deep::Matcher のmatcher に変換
- 開発環境、テスト環境の設定値が、matcher にあうか比較
です
例えば、以下のような本番設定があったとして..
# production.pl { servers => [ 'XX.XX.XXX.XXX:11211', 'XX.XX.XXX.YYY:11211', ], options => { utf8 => 1, }, }
再帰的にmatcherに変換してあげます
use Test::Deep::Matcher; use Test::Deep qw//; sub convert_matcher { my $v = shift; if (!ref $v) { return Data::Util::is_integer($v) ? is_integer : Data::Util::is_number($v) ? is_number : Data::Util::is_string($v) ? is_string : Data::Util::is_value($v) ? is_value : undef; } elsif(ref $v eq 'ARRAY') { return Test::Deep::array_each(convert_matcher($v->[0])) # XXX: 仮定 } elsif(rev $v eq 'HASH') { return +{ map { $_ => convert_matcher($v->{$_}) } keys %$v } } }
あとは比較するだけです
my $expect = convert_matcher($production_conf) cmp_deeply $development_conf, $expect;
(余談)
- 上の例では、本番環境の設定から(雑な)型推定をしました
- 設定の型定義を用意しておけるなら、その方が良いかもしれません
- 異常値などの定義をしやすいですし
以下、crystal
の例です
require "json" class Config JSON.mapping({ servers: String, options: { type: ServerOptions }, }) end class ServerOptions JSON.mapping({ utf8: Int32 }) end
Fixture のテスト
リレーションチェックのため、 DBIx::Schema::DSL, SQL::Translator::Schema を利用しています
チェックには、外部キー制約を利用します
実際のアプリケーションでの利用は、諸事情 でしていないですが、
テストでの利用では最高に便利です
(この辺の外部キーありなしのスイッチを、no_fk_output/output
だけで簡単にできるのが、DBIx::Schema::DSL
めっちゃ便利だーってなって便利です)
流れは、
- 外部キー制約つきのスキーマを用意して、
INSERT
する
だけです。 ただ、エラーメッセージを、人間が読みやすい形にするため、地味にループを回すようなコードにしています:p
# Schema use 5.014002; package MyProj::DB::Schema { use DBIx::Schema::DSL; create_table 'module' => columns { integer 'id', primary_key, auto_increment; varchar 'name'; integer 'author_id'; add_index 'author_id_idx' => ['author_id']; belongs_to 'author'; }; create_table 'author' => columns { integer 'id', primary_key, auto_increment; varchar 'name', unique; }; }
# belongs_to.t $db->execute(MyProj::DB::Schema->output); my $schema = MyProj::DB::Schema->context->schema; my $module_schema = $schema->get_table('module'); my $constraints = $module_schema->fkey_constraints; for my $fkey (@$constraints) { my $ref_table = $fkey->reference_table; my @errors = try_load($ref_table); ok !@errors or note explain @errors; } sub try_load { my ($table) = @_; my @errors; for my $row (@{$FIXTURE_DATA{$table}}) { try { $db->insert($table => $row); } catch { push @errors => shift; }; } return @errors; }
まとめ
アプリケーション設定ファイルのテスト
とFixtureのテスト
の実装例を紹介しました
明日は、 nekobato さんです!