27:必要十分なテストデータを用意する

ユニットテストを実行しているときに徐々に伸びていくテスト実行時間に不安を覚えたことはありませんか? ここではテスト実行時間を短くできる方法について説明します。

プログラミング迷子: 境界値テストのために1万レコード必要なんです

  • 後輩W:テストのレビューお願いします。

  • 先輩T:ほいほい。なんかこのテスト実行するのに時間かかるね。

  • 後輩W:あー、あそこのテストで、テスト用のデータいっぱい生成してるからですかね?

  • 先輩T:ふむふむ。なるほど。こんなにデータ作らなくてもいいかもね。

  • 後輩W:どういうことです? そこは1万件データがあるとif分岐してXXの処理を挟むんですが。

  • 先輩T:そうだね、本当にテストしたいのはそのif分岐が条件に従って実行されるかってことだよね?

  • 後輩W:はい。

  • 先輩T:その条件となる1万件はテストのときには任意の数に変更できるようにすれば、無駄にテストデータを生成せずにテストできるよね。

  • 後輩W:なるほどー。

具体的な失敗

DjangoのORMからSpamモデルの件数をカウントして、件数が10,000件を超えるかどうかで 結果が変わるようなコードがあるとします。 このテストコードを書く場合、10,000件のSpamモデルのデータを用意しないと、ifの分岐をテストできません。 テストを実行するたびに、毎回10,000件のデータを生成していては時間がかかりすぎます。

def is_enough_spam(piyo_id):
    if Spam.objects.filter(piyo_id=piyo_id).count() > 10000:
        return True
    else:
        return False

ベストプラクティス

上記コードでは、TrueとFalseを返すことがテストできれば良いので、テストをしやすいように、条件となる数値を引数として用意しましょう。 テストのときにnum_of_spamを 任意の数、たとえば1に変えてテストができます。

def is_enough_spam(piyo_id, num_of_spam=10000):
    if Spam.objects.filter(piyo_id=piyo_id).count() > num_of_spam:
        return True
    else:
        return False

引数で渡せないのであれば条件となる数字を定数化して、それをモックで置き換えるのでも良いでしょう。

cover

(中略)詳細は書籍 自走プログラマー をご参照ください