あなたは正しいです、あなたのテストはrandom
モジュールがその仕事をしていることを確かめるべきではありません ユニットテストは、クラス自体をテストするだけで、他のコードとの相互作用はテストしません(個別にテストする必要があります)。
もちろん、コードでrandom.randint()
間違った使い方をすることは完全に可能です。または、random.randrange(1, self._sides)
代わりに呼び出して、ダイスが最高値をスローすることはありませんが、それは別の種類のバグであり、ユニットテストでキャッチできるバグではありません。その場合、die
ユニットは設計どおりに動作していますが、設計自体に欠陥がありました。
この場合、モックを使用して関数を置き換え、randint()
関数が正しく呼び出されたことを確認するだけです。Python 3.3以降には、このタイプのテストを処理するunittest.mock
モジュールが付属していますが、外部mock
パッケージを古いバージョンにインストールして、まったく同じ機能を取得できます
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
モッキングにより、テストは非常に簡単になりました。本当に2つのケースしかありません。6面ダイスのデフォルトケース、およびカスタムサイドケース。
randint()
のグローバル名前空間の関数を一時的に置き換える他の方法Die
がありmock
ますが、モジュールはこれを最も簡単にします。ここでの@mock.patch
デコレータは、テストケースのすべてのテストメソッドに適用されます。各テストメソッドには追加の引数であるモックrandom.randint()
関数が渡されるため、モックが実際に正しく呼び出されたかどうかをテストすることができます。return_value
私たちがいることを確認することができますので、それが呼び出されたモックから返されたものを引数の指定die.roll()
方法は、確かに私たちに「ランダム」の結果を返しました。
ここでは、別のPythonユニットテストのベストプラクティスを使用しました。テストの一環として、テスト対象のクラスをインポートします。この_make_one
メソッドはtest内でインポートとインスタンス化を行います。そのため、元のモジュールのインポートを妨げる構文エラーやその他の間違いを犯した場合でも、テストモジュールはロードされます。
このようにして、モジュールコード自体に間違いを犯した場合でも、テストが実行されます。それらは失敗し、コードのエラーについて通知します。
明確にするために、上記のテストは極端に単純化されています。ここでの目標はrandom.randint()
、たとえば正しい引数で呼び出されたものをテストすることではありません。その代わり、目標は、特定の入力が与えられた場合にユニットが正しい結果を生成していることをテストすることです。これらの入力には、テストされていない他のユニットの結果が含まれます。random.randint()
メソッドをモックすることにより、コードへの別の入力を制御することができます。
では現実世界のテスト、あなたのユニットアンダーテストで実際のコードはより複雑になるだろう。APIに渡される入力と他のユニットがどのように呼び出されるかとの関係は興味深いものになる可能性があり、モッキングにより中間結果へのアクセスが可能になり、それらの呼び出しの戻り値を設定できるようになります。
たとえば、サードパーティのOAuth2サービス(マルチステージインタラクション)に対してユーザーを認証するコードでは、コードがそのサードパーティサービスに適切なデータを渡していることをテストし、サードパーティサービスが返されるため、完全なOAuth2サーバーを自分で構築することなく、さまざまなシナリオをシミュレートできます。ここでは、最初の応答からの情報が正しく処理され、2番目の段階の呼び出しに渡されていることをテストすることが重要です。そのため、模擬サービスが正しく呼び出されていることを確認する必要があります。