let s database_testing

Post on 06-Jul-2015

1.284 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

let's database testing!!

2010/10/16 YAPC::Asia 2010@xaicron

自己紹介

name: Yuji Shimada ( 嶋田 裕二 )

works: DeNAtwitter: @xaicronblog: http://blog.livedoor.jp/xaicron/

皆さん

データーベース処理のテスト

してますか?

DB のテストをすると

この SELECT なんにもマッチしない...INSERT したデータが文字化けしてるやん!UPDATE や DELETE に WHERE 付け忘れてて全件あばばば TRIGGER が間違ってて、データ壊れた。。。

という事態を未然に防げます!

というか。。。

永続的なストレージに実際に入出力があるんだから

テストするのはあたりまえですね!

今回は MySQL に焦点を絞ってお話します

ORM の話もしません

基本的には 生DBI をつかってやります

Haw To Testing

鉄則

ローカルでテストできる環境を作ること!!

よくない例

ステージング環境のDBに接続してテストする本番は MySQL だけど、テストでは SQLite を使う自分のローカルに立ち上がっている MySQL  をテストに使う

 

実際に存在している DB を使ってテストすると、毎回データが変わってテストにならない本番は MySQL なのに テストでは SQLite とかは意味がない

Test の大まかな流れ

Test::mysqld を使って毎回クリーンな mysql を立ち上げるTest::Fixture::DBI を使ってテストデータを突っ込むDB 接続して、実際にデータの入出力が行われているかテストそして伝説へ...

Test::mysqld

new するだけで、lcoal に 新規 mysql が立ち上がるDESTROY が走ったら、自動的に mysql を落とすAuthor: kazuhooku

DEMO

Test::Fixture::DBI

table 作ったり、 procedure / function / trigger 作ったり、data ぶっこんだりできる既存の DB から schema 定義をもってきたり、指定のレコードをとって来たりできる

make_*_yaml.pl で fixture や database 定義を YAML に吐き出せる

Author: ZIGOROu, (test: xaicron)

DEMO

なかなか便利ですが

テスト毎にこれを毎回書くのはめんどいので

適当に組み合わせたTest Module を書いて使うと

いいでしょう

Test::Foo::Fixture::DBIみたいな名前にして

setup_

実際のテストの書き方

の前に

DBI を直接扱う上で便利なモジュールを紹介します

DBI と親和性の高いモジュール

SQL::AbstractDBIx::DBHResolverDBIx::Connector

DBIx::Connector ->DBIx::DBHResolver ->

DBI

という感じでラップするとなかなかいい感じ

DBIx::Connector

DBI の超薄いラッパー

$dbh を局所化できる多分最大の利点

fixup => で再接続トランザクション処理をよしなにやってくれる

DBIx::DBHResolver

DBI 専用の container みたいなノリ複数の DB に接続するのに便利

Master / SlaveUser と Diary が別の DB

Sharding していてもかなり直感的

DBIx::Connector とも協調しやすい

+SQL::Abstract

my $row = $model->connector('SLAVE')->txn(fixup => sub {        my $dbh = shift;        my ($stmt, @bind) = $model->sql->select(...);        return $dbh->selectrow_hashref($stmt, undef, @bind);});

みたないな感じでつかえる

ようやく実際のテストの話

SELECT した結果を返すもののテスト

my $row = try {    $self->connector('SLAVE', $user_id)->run(fixup => sub {        my $dbh = shift;        my ($stmt, @bind) = $self->sql->select(            'user_data',            [qw/id name/],            { id => $user_id, disabled => 0 },          );          $dbh->selectrow_hashref($stmt, undef, @bind);    });}catch {    my $e = $_;    ...};

mysqld に fixture を入れる実際にたたいて値を取得取得した値が正しいかチェック

DEMO

INSERT のテスト

try {    my $seq = $self->next_seq('MASTER', 'seq_tweet');    $self->connector('MASTER', $user_id)->run(fixup => sub {        my $dbh = shift;        my ($stmt, @bind) = $self->sql->insert(            'tweet',            { id => $seq, ... },        );        $dbh->do($stmt, undef, @bind);        $dbh->commit;    });}catch {    my $e = $_;};

実際にたたいて値を入力正常に INSERT されているかチェック

UPDATE とか DELETE も同じ感じ

特別に難しいことはやっていない

すべての SQL に対して地道にテストを書きましょう

PROCEDURE / FUNCTION/ TRIGGER

のテスト

FUNCTION とは

そのまんま一連のSQLを関数化できるCALL function_name(args) で呼べる値を返すので、参照系に使える

PROCEDURE と

値を返さない FUNCTION主に更新用途 CALL procedure_name(args) で呼べる

TRIGGER とは

テーブルの更新タイミングで発火INSERT / UPDATE / DELETE

SQL なら何でも書ける

PROCEDURE をよく使う (更新なので)

FUNCTION のテスト

SELECT とおんなじ

PROCEDURE / TRIGGERのテスト

INSERT / UPDATE /DELETEとおんなじ

Test::mysqld の問題点

make test したときにすっごい時間がかかる orz

1テスト毎に mysqld を立ち上げて落としてるから仕方ないよね

なんとかしたい

なんとかしたい

Makefile の書き換え大変です!

Module かいたよーModule::Install::ExtendsMakeTest

replace_default_make_test(    includes         => ['t/lib'],    modules          => ['Test::MyApp::DB'],    before_run_codes => [        sub {            $SIG{INT} = sub { CORE::exit 1 };            my $db = Test::MyApp::DB->setup;            $ENV{TEST_MY_SOCKET} = $db->my_cnf->{socket};        },      ],  );

みたいな感じで書くとmake test 時に mysqld

が立ち上がる

あとは、socket ファイルとかを指定して接続すれば OK

$ENV に値があったら立ち上がっている mysqld を使って、

なかったら 新規に立ち上げるようにしておけばいい

DEMO

というわけで

プログラムから扱いそうなDB の処理は

ちゃんとテストできる!!

ので、テストを書きましょう

自分(とみんな)のために

まとめ

地道にやっていけば DB 処理の大部分をテスト結構ツール類が充実してきているでもまだ自分で書く部分が多い印象割とこの辺のノウハウがたまりつつあるので、よくある処理は Module 化したい

DEMO で使った適当なプロダクト

http://github.com/xaicron/Mayoi

ご清聴ありがとうございました

Questions?

閑話休題

top related