ククログ

株式会社クリアコード > ククログ > PGroongaのユニットテスト

PGroongaのユニットテスト

ユニットテストについてお勉強中の阿部です。

今回はPGroongaのユニットテストについて説明します。 どのようなツールを使って、どのようなテストをしているのかと新たにテストを追加する方法を説明します。

Groonga開発者に聞け!(グルカイ!)第60回でも 解説しているので、あわせてご覧ください!

PGroongaのユニットテストで使っているツール

PGroongaでは以下の2つを使っています。

  1. pg_regress
    • PostgreSQLに含まれているリグレッションテストツール
    • SQLを実行して期待通りの結果が得られるかテストできる
  2. 独自のテストツール
    • ストリーミングレプリーケーションのテストが便利にできる
    • クラッシュしたときのテストが便利にできる

pg_regressを使ったテストで十分な場合がほとんどだと思いますが、PGroongaではレプリーケーションをしたときの プライマリー側の挙動のテスト、スタンバイ側の挙動のテストや、PGroongaがクラッシュした場合の挙動のテストなども 必要でした。 そのようなテストの場合pg_regressではテストを書くのが大変だったため、独自のテストツールを使って テストを実行しています。

以降で「pg_regress」と「独自のテストツール」の特徴と新規でテストを追加する方法ついて説明します。

pg_regress: 概要

「テストしたいSQL」と「期待される実行結果」の2つのファイルを用意すればテストできます。 「テストしたいSQL」を実行した結果と「期待される実行結果」が一致しているかをテストします。

具体例を見るのが手っ取り早いので、以下に具体例を記載します。

「テストしたいSQL」例の一部:

SELECT id, content
  FROM memos
 WHERE content &@~ 'rdbms OR engine';

全文掲載すると長くなるのでひとつの SELECT のみ掲載しました。 このSQLを実行して、以下の結果と同じになるかをテストする非常にわかりやすいテストです。

「期待される実行結果」例の一部:

SELECT id, content
  FROM memos
 WHERE content &@~ 'rdbms OR engine';
 id |                 content
----+------------------------------------------
  1 | PostgreSQL is a RDBMS.
  2 | Groonga is fast full text search engine.
(2 rows)

pg_regress: 新規でテストを追加する

実は上記の説明は少し正確ではありません。

「テストしたいSQL」と「期待される実行結果」の2つのファイルを用意

と書きましたが、実はテストを新規で追加するときは「テストしたいSQL」だけ用意すれば良いです。

流れは以下の通りです。

  1. 「テストしたいSQL」を用意する
    • PGroongaでいうと sql/ 以下に新たな .sql ファイルを追加
  2. 「テストしたいSQL」のみを追加した状態で pg_regress を実行
  3. 「期待される実行結果」を用意していないので、実行結果との差分が表示される。その内容を確認
    • 「期待される実行結果」がないので実行結果の全文が表示される。それが期待通りか確認する
  4. 3で表示された結果が期待通りであれば、その結果から「期待される実行結果」を作る
    • PGroongaでいうと results/ 以下にテスト実行結果が出力される
      • sql/full-text-search/vacuum.sql のテスト実行結果であれば、results/full-text-search/vacuum.out に出力される
    • それをコピーして expected/ 以下に配置する
      • sql/full-text-search/vacuum.sql のテスト実行結果であれば、results/full-text-search/vacuum.outexpected/full-text-search/vacuum.out にコピーする
    • 以上で「期待される実行結果」の作成が完了
  5. pg_regressを実行してテストがパスすることを確認する

ということで、「テストしたいSQL」のみ用意してpg_regressの結果から「期待される実行結果」を作れます。 これで新たなテストの追加が完了です。

独自のテストツール: 概要

Rubyで書かれた独自ツールです。 細かく説明すると長くなるので、便利ポイントを3つだけ紹介します。

レプリーケーションのテストが簡単にできる

https://github.com/pgroonga/pgroonga/blob/3.2.1/test/test-streaming-replication.rb

class StreamingReplicationTestCase < Test::Unit::TestCase
  include Helpers::Sandbox

  setup :setup_standby_db
  teardown :teardown_standby_db
  ...
end

setup :setup_standby_dbteardown :teardown_standby_db と書くとレプリーケーションの スタンバイサーバの用意とお片付けもしてくれます。(プライマリーサーバは明示的に指定しなくても毎回起動してくれます。)

これらとrun_sqlrun_sql_standbyを使うことでレプリケーションのプライマリー側、スタンバイ側の挙動のテストが簡単に行えます。

補足: run_sqlrun_sql_standby

メソッド名から想像できると思いますが run_sql はクエリを実行します。これはプライマリーサーバでクエリを実行します。

run_sql_standby メソッドもあり、こちらを実行するとスタンバイサーバでクエリを実行します。

設定変更を簡単にできる

その都度PostgreSQLの設定を変えてテストしたいときがあります。 pg_regressは起動済のPostgreSQLサーバに対してテストを実行するので、そういった場合にテストしにくいです。

https://github.com/pgroonga/pgroonga/blob/3.2.1/test/test-pgroonga-crash-safer.rb

  def additional_configurations
    <<-CONFIG
pgroonga.enable_crash_safe = yes
pgroonga.enable_wal = yes
pgroonga.log_level = debug
pgroonga_crash_safer.flush_naptime = #{flush_naptime}
pgroonga_crash_safer.log_level = debug
    CONFIG
  end

additional_configurationsというメソッドを定義して、そこに設定したPostgreSQLの設定を書くと、 テスト実行時にその設定で起動したPostgreSQLサーバでテストが実行できます。

ログを確認できる

https://github.com/pgroonga/pgroonga/blob/3.2.1/test/test-vacuum.rb

「バックグラウンドで動くモジュール」を開発していると、 ログの内容もテストしたくなります。 そのような場面でもこの独自のテストツールは便利です。

    pgroonga_log = @postgresql.read_pgroonga_log
    assert_equal(["pgroonga: unmap DB because VACUUM was executed"],
                 pgroonga_log.scan(/pgroonga: unmap.*$/),
                 pgroonga_log)

@postgresql.read_pgroonga_logでPGroongaのログの内容を取得できるのでそれを使ってテストできます。 PostgreSQLのログであれば@postgresql.read_log で取得できます。

独自のテストツール: テストを追加する

上記で説明した独自の便利メソッドを駆使して追加します。 基本的にはRubyのtest-unitなので、test-unitを書くときと書き方は一緒です。

かなり簡単に書くとrun_sqlでクエリを実行する、それが期待通りかassert_equalするテストを追加します、 という感じです。

  ...

  setup do
    # CREATE TABLEなど準備
    # ...
  end

  test "example" do
    # 期待される結果
    expected_output = "..."
    expected_error = "..."
    # run_sqlで実際に実行
    acutal_output, actual_error = run_sql("SELECT * FROM example")
    # テストする
    assert_equal([expected_output, expected_error]
                 [acutal_output, actual_error])
  end

  ...

まとめ

詳細を説明するにはスペースが狭すぎたので概要の説明のみにとどめましたが、PGroongaのユニットテストについて説明しました。

pg_regressはPGroonga以外でも使われているのでぜひご活用ください!

PGroongaの独自のテストツールは非常に簡単にテストが書けて開発スピードが上がります。 そのようなテストツールの開発などもサポートいたしますので、ユニットテストでお困りの際は お問い合わせよりお問い合わせください。