UTで「存在しないオブジェクト」を扱いたいときの書き方

概要

過去の実装を振り返っていたら、面白いコードを見つけたので晒しておこう。

まえおき

ここに登場するコードは以下で実装されたものを前提としている。

例やコードは、サンプル向けにアレンジしたもののため、違和感はご愛嬌。

やりたかったこと

書籍情報を取得するメソッドの UT で、書籍が存在しなかった場合は BookNotFoundError の例外が送出されることを確認するテストを書きたかった。
実装したテストコードが以下である。


def test_get_by_id_raises_book_not_found_error(self):
  """書籍が存在しない場合は例外を送出すること"""

  from book.exceptions import BookNotFoundError

  # arrange
  book = BookFactory()
  book.delete()

  # act/assert
  with pytest.raises(BookNotFoundError):
        BookClass.get_by_id(id=book.id)

違和感にお気づきだろうか…w

このコードの問題点

上記のコードには、以下の点でイマイチである。


  • 「存在しない書籍」を表すため、わざわざ書籍オブジェクトを作成して消している…
  • このコードを読んだ人の頭の中を「?」で埋め尽くす可能性が非常に高い

なぜこうなった?

削除すれば「存在しない」を表せると思った。
それはそうなんだが、完全に脳みそが溶けていたと思われる 🫠

まぁ、当時はいろいろいっぱいいっぱいだったのだろう (語彙

どうするとよさそうか?

  • UT 上はもともと書籍は存在しないのだから、BookFactory() する必要はない
  • BookClass.get_by_id() には存在しない id を指定すればよい

def test_get_by_id_raises_book_not_found_error(self):
  """書籍が存在しない場合は例外を送出すること"""

  from book.exceptions import BookNotFoundError

  # act/assert
  with pytest.raises(BookNotFoundError):
        BookClass.get_by_id(id=999)

シンプルにこれでよいのだ。
以上。

おわり

脳みそが溶けているときに書いたコードを見るのは面白い ()