iakioの日記 RSSフィード

2008-10-17

regression testでSQLをテストする

| 23:43 | regression testでSQLをテストする - iakioの日記 を含むブックマーク はてなブックマーク - regression testでSQLをテストする - iakioの日記

PostgreSQLでボーリングのスコア計算 - iakioの日記 - postgresqlグループ

誰も気にしてないでしょうが間違ってました。最終フレームで3投目まで投げないと合計がおかしいです。left joinしないとダメかなぁ。

ここはもうテストするしかない。ここはpgTAPか!と思ったけどもうひとつ試してみたい方法があったのでpgTAPはまた今度。

PostgreSQLには、PostgreSQL自身やcontribモジュールのテストを行うregression testの仕組みがあります。これを使ってsqlだけをテストしてみます。今回も長文です。

単純なテストの例

まずおもむろにMakefileを作ります。PGXSを使って拡張モジュールを作る要領です。

REGRESS = test

PGXS := $(shell pg_config --pgxs)
include $(PGXS)

これだけ。REGRESSにはテスト内容を書いたsqlファイルの名前を指定します。下二行はきまり文句です。まだテスト自体作ってませんがこれでmake installcheckしてみましょう。

$ gmake installcheck
/path/to/pgsql/current/lib/pgxs/src/makefiles/../../src/test/regress/pg_regress --inputdir=. --psqldir=/path/to/pgsql/current/bin --dbname=contrib_regression test
(using postmaster on Unix socket, default port)
============== dropping database "contrib_regression" ==============
DROP DATABASE
============== creating database "contrib_regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries        ==============
test test                 ... cannot open /tmp/bowling/sql/test.sql: No such file or directory
diff: /tmp/bowling/expected/test.out: No such file or directory
diff: /tmp/bowling/results/test.out: No such file or directory
diff command failed with status 512: diff -w "/tmp/bowling/expected/test.out" "/tmp/bowling/results/test.out" > "/tmp/bowling/results/test.out.diff"
gmake: *** [installcheck] Error 2

色々エラーが出ましたが、これでだいたいやるべきことはわかりました。

  • sql, expectedというディレクトリを作る
  • sql/test.sqlにテストを書く
  • expected/test.outに期待される結果を書く

では適当なテストと空っぽのexpectedを作ります。

$ mkdir sql expected
$ echo "select 1" > sql/test.sql
$ touch expected/test.out

実行

(using postmaster on Unix socket, default port)
============== dropping database "contrib_regression" ==============
DROP DATABASE
============== creating database "contrib_regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries        ==============
test test                 ... FAILED

======================
 1 of 1 tests failed.
======================

The differences that caused some tests to fail can be viewed in the
file "/tmp/bowling/regression.diffs".  A copy of the test summary that you see
above is saved in the file "/tmp/bowling/regression.out".

gmake: *** [installcheck] Error 1

いい感じで失敗しました。このテストのために毎回CREATE DATABASEするんで効率は良くないっちゃ良くないですが。テストの実行結果はpsqlの出力になります。results/test.outを見てみましょう。

$ cat results/test.out
select 1
 ?column?
----------
        1
(1 row)

期待した結果なのでこれをexpected/test.outにコピーしてもう一度実行。

(using postmaster on Unix socket, default port)
============== dropping database "contrib_regression" ==============
DROP DATABASE
============== creating database "contrib_regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries        ==============
test test                 ... ok

=====================
 All 1 tests passed.
=====================

パスしました。パチパチ。

受け入れテスト

ではボーリングスコア計算のsqlのテストをします。あの長いsqlをすべてのテストに書くのは大変なので、別ファイルに書いておきます。ここではMakefileと同じディレクトリのbowling.sqlというファイルに書いておくことにします。

次にまず受け入れテストを作ります。

-- sql/acceptance.sql
create table score(idx int, pins int);
copy score from stdin;
1   1
2   4
3   4
4   5
5   6
6   4
7   5
8   5
9   10
10  0
11  1
12  7
13  3
14  6
15  4
16  10
17  2
18  8
19  6
\.
\set ECHO
\i bowling.sql

psqlの\iコマンドでbowling.sqlを読み込んでいます。results/acceptance.outにあの長いsqlが含まれないようにするために、\set ECHOで出力を抑止しています。Makefileにテストを追加します。

REGRESS = acceptance

んで、テストを実行。expected/acceptance.outを作っていないので当然失敗します。results/acceptance.outは、

-- sql/acceptance.sql
create table score(idx int, pins int);
copy score from stdin;
\set ECHO
 sum
-----
 133
(1 row)

オーケー。これをexpectedにコピーしてテストがパスすることを確認しましょう。

すべて1ピンの場合

次に、20回すべて1ピンだった場合です。REGRESSに指定したsqlは順番に実行されるので、最初にscoreテーブルを空にしています。トランザクションを使ってrollbackしてもいいかもしれません。

-- all_one.sql
truncate score;
copy score from stdin;
1   1
2   1
3   1
4   1
5   1
6   1
7   1
8   1
9   1
10  1
11  1
12  1
13  1
14  1
15  1
16  1
17  1
18  1
19  1
20  1
\.
\set ECHO
\i bowling.sql

そこはgenerate_seriesダロという声も聞こえてきそうですが。Makefileにテストを追加します。あといい加減make installcheckと打つのが面倒になってきたのでデフォルトターゲットをinstallcheckにしておきます。

all: installcheck
REGRESS = acceptance all_one

PGXS := $(shell pg_config --pgxs)
include $(PGXS)

んでテスト実行。results/all_one.outは、

-- sql/all_one.sql
truncate score;
copy score from stdin;
\set ECHO
 sum
-----
  18
(1 row)

ダメダメですね。正解は20なので20に書き換えてexpectedにコピーしておきます。

直す

で、何がダメだったか解説はしませんが、直したsqlはコチラ。

with recursive
s(idx, pins1, pins2, pins3) as (
    select s1.idx, s1.pins, s2.pins, s3.pins
      from score s1
      left join score s2 on (s2.idx = s1.idx + 1)
      left join score s3 on (s3.idx = s1.idx + 2)
),
f(idx, pins1, pins2, pins3) as (
    select idx, pins1, pins2, pins3 from s where idx = 1
     union all
    select s.idx, s.pins1, s.pins2, s.pins3
      from s join f
        on (s.idx = f.idx + case when f.pins1 = 10 then 1 else 2 end)
),
sof(idx, pins1, pins2, pins3, score_of_frame) as (
    select idx
         , pins1, pins2, pins3
         , case when pins1 = 10 then pins1 + pins2 + pins3
                when pins1 + pins2 = 10 then pins1 + pins2 + pins3
                else pins1 + pins2
            end as score_of_frame
           from f
)
select sum(score_of_frame) from sof;

で、テスト。

============== dropping database "contrib_regression" ==============
DROP DATABASE
============== creating database "contrib_regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries        ==============
test acceptance           ... ok
test all_one              ... ok

=====================
 All 2 tests passed.
=====================

通りました。パチパチ。本当かな。

追記:PostgreSQL8.2以上ぐらいじゃないと使えないかもしれません。

KamerynKameryn2012/01/11 18:23Smart thinking - a celver way of looking at it.

bdlzgazpoddbdlzgazpodd2012/01/13 23:407YJbDe , [url=http://lmrjhfyrvnxn.com/]lmrjhfyrvnxn[/url], [link=http://sjhrtoqoepta.com/]sjhrtoqoepta[/link], http://hegxfpzjchut.com/

wfnkmoylufkwfnkmoylufk2012/01/14 20:4132EApZ <a href="http://wuabqmmswmgn.com/">wuabqmmswmgn</a>

kbdnqlffpkbdnqlffp2012/01/16 20:577FHBaK , [url=http://wehgsrhmfdee.com/]wehgsrhmfdee[/url], [link=http://zbsiuwqfgvea.com/]zbsiuwqfgvea[/link], http://fbbyuuctiiij.com/

トラックバック - http://postgresql.g.hatena.ne.jp/iakio/20081017