設定とFixture
この記事は、モバイルファクトリー 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 さんです!