たまめ的生活記録

日々で思ったこととか、技術的なこととか。

Pythonでtry-exceptする引数付きデコレータを単体テスト

先日Pythonの引数付きデコレータをテストしたいということがありました。
結構調べるのが大変だったので、メモっておきます。

引数付きデコレータ

今回テストしたかったのはこんな感じのデコレータです。
何も起きなければデコレートした関数をそのまま実行し、例外が起きた時に引数で指定した値を返します。

try_except decorator

これほんとネスト深くなって嫌ですねー。
何はともあれ、このデコレータを使えばこんな感じで、例外処理を簡単に使えるようになります。

decorate get_json

この @try_except をテストします。

テスト

デコレータは引数に関数を持つので、その関数をモックとして作ってあげなきゃいけません。
こういう時はunittestパッケージのMagicMockを使ってあげると楽に書けます。
また、戻り値や例外なんかも設定できます。

mock_func for test decorator

今回は、次の二つをテストします。

  • 例外が起きなかった場合にデコレートされた関数の戻り値が返ること
  • 例外が起きた時にデコレータに渡した引数が返ること

ここで注意なのですが、デコレータそのものをテストする際は、デコレータを直接関数として呼び出す必要があります。
引数付きデコレータの場合は関数が3つネストされているので、3回の関数呼び出しが必要です。
以上をまとめると、実際のテストコードはこんな感じになります。

test try_except_deco

無事テストできました。
とにかく大事なのはこの二つですね。

  • デコレートする関数をMagicMockを使ってモック化する
  • デコレータ自身を関数として呼び出す

参考

pythonのデコレータを使ってお手軽ベンチマーク - BlankTar
[Python] Exceptionをraiseするモック関数の作り方