testing.redis を作りました。

testing.* シリーズも、mysqld, cassandra, postgresql と自分が使うであろうものは一段落していたのですが、
隣の同僚がついでに redis やっちゃえよ的なことを言ってきたので、勢いそのまま testing.redis を作りました。

このモジュールを作る際にはじめて redis に触ったので、本末転倒感がすごいです。

testing.redis も他の testing.* シリーズと同様に、テスト用の redis インスタンスを起動するライブラリです。
こんな感じでおもむろに redis を起動することができます。

import redis
import testing.redis

with testing.redis.RedisServer() as redis_server:
    r = redis.Redis(**redis_server.dsn())

この例だと with 文を抜けると redis インスタンスは破棄されるので、使い捨て感覚で redis を利用できます。

データベースを使い捨てにすると、テストを書くときに事前の状態を気にしなくて済むようになるので、
シンプルなテストを書くことができるのではないかと思います。

事前にデータを用意したい

最初の状態を意識しなくて良いというのは一見楽なのですが、あらかじめデータ(fixtures)を突っ込んでおきたいというニーズはあります。
そのために、testing.* では「事前にデータを用意しておく」方法を提供しています。
それが copy_data_from キーワードです。

import redis
import testing.redis

with testing.redis.RedisServer(copy_data_from='/path/to/database') as redis_server:
    r = redis.Redis(**redis_server.dsn())

このように指定しておくと、/path/to/database にあるデータベースファイルをコピーして
redis インスタンスの初期データにすることができます。

マスタデータを持たせておきたいときなどはこうしておくと楽かもしれません。
(もちろん fixture を登録するスクリプトを書いても良いのですが、ちょっと実行コストが上がります)

unittest と組み合わせて使う

python 標準のテストフレームワーク、unittest と組み合わせるには次のようにします。

import unittest
import testing.redis

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.redis = testing.redis.RedisServer()

    def tearDown(self):
        self.redis.stop()

シンプルに setUp() と tearDown() で redis の起動と終了をやるだけですね。

なお、@skipIfNotInstalled デコレータを使うと redis-server が入っていない環境ではテストをスキップするようになります。
個々人の開発環境ではユニットテストだけにとどめて、CI サーバ上でだけ redis を使ったテストをしたい場合などにつかってください。

class MyTestCase(unittest.TestCase):
    @testing.redis.skipIfNotInstalled
    def my_test_case_using_redis_server(self):
        # ...

まとめ

  • testing.redis 作ったよ
  • ついでに testing.* についてまとめてみたよ
  • 気になったら使ってみてください