Python assert 例外
この記事では、テストの単位としての assert
を理解し、関数が必ずしも実行を終了せずに例外(コード実行中に検出されたエラー)をスローできることをテストします。つまり、スローされた例外はカプセル化されます。
このテストは、例外が発生した場合に合格します。予期されたもの以外の別の例外がスローされた場合、エラーがスローされます。発生した例外がまったくない場合、テストは失敗します。
コンテキストマネージャで Python の assert 例外をキャッチする
一般的な Python の概念で必然的に必要な場合にリソースの割り当てと解放を許可する方法と同様に、ここでのコンテキストは、テスト中にスローされる実際の例外オブジェクトを取得します。
発生した例外に対して追加のパフォーマンスチェックが必要な場合は、この例外属性をオブジェクトに格納します。
関数が失敗するか、例外がスローされるかどうかをテストするために、unittest
モジュールの TestCase.assertRaises
を使用します。
コンテキストマネージャを使用した実際の例を見てみましょう。
import unittest
class TestCase(unittest.TestCase):
def test_nameerror(self):
with self.assertRaises(Exception):
100 * (someNumber / 5)
if __name__ == "__main__":
unittest.main()
出力:
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
サンプルコードでは、例外がスローされることが予想されるため、テストに合格しています。5 を未定義の変数 someNumber
で除算しています。したがって、この関数は NameError
例外をスローします。したがって、出力の最初の行に .
が表示されているように、テストはパスしています。
例外がスローされないときにテストが失敗する例を見てみましょう。
import unittest
class TestCase(unittest.TestCase):
def test_nameerror(self):
with self.assertRaises(Exception):
someNumber = 10
100 * (someNumber / 5)
if __name__ == "__main__":
unittest.main()
出力:
F
======================================================================
FAIL: test_nameerror (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last): File "c:\Users\Neema\Desktop\Article Requirement Spec and Example
Articles\Article Requirement Spec
and Example Articles\fah.py", line 106, in test_nameerror
100 * (someNumber/5)
AssertionError: Exception not raised
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
このサンプルコードでは、someNumber
の値を定義し、それを使用して算術式を実行します。
出力は、テストが期待どおりに失敗したことを示しています。someNumber
の定義済みの値が存在するため、今回は NameError
例外がスローされることはありません。
次の例のように、ユーザー定義の例外を使用してコンテキストマネージャーを実装することもできます。
import unittest
def user_function():
raise Exception("A user-defined exception")
class MyTestCase(unittest.TestCase):
def test_userexception(self):
with self.assertRaises(Exception) as context:
user_function()
self.assertTrue("A user-defined exception" in str(context.exception))
if __name__ == "__main__":
unittest.main()
出力:
.
----------------------------------------------------------------------
Ran 1 test in 0.006s
OK
TypeError が発生しないように、
str
を使用してcontext.exception
を囲むことを忘れないでください。
ユニットテストでテスト値を true と比較する unittest
ライブラリである assertTrue
を紹介します。
assertTrue の代わりに assertIn
を使用することもできます。
例:
import unittest
def user_function():
raise Exception("A use defined exception")
class MyTestCase(unittest.TestCase):
def test_userexception(self):
with self.assertRaises(Exception) as context:
user_function()
self.assertIn("A use defined exception", str(context.exception))
if __name__ == "__main__":
unittest.main()
テストに合格した場合と同じ出力が生成されます。
キーワード引数を使用して Python アサート例外をキャッチする
assertRaises()
に例外を渡すだけのコンテキストマネージャーとは異なり、例外を呼び出すためのキーワード引数として関数呼び出しと関数のパラメーターも渡します。
構文
assertRaises(exception, function, *args, **keywords)
例:
import unittest
class MyTestCase(unittest.TestCase):
def test_division_by_error(self):
import operator
self.assertRaises(ZeroDivisionError, operator.floordiv, 55, 0)
if __name__ == "__main__":
unittest.main()
出力:
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
上記のサンプルコードでは、キーワード引数とともに assertRaises()
を使用しました。数値をゼロで除算しようとした後に予期される ZeroDivisionError
例外を渡しました。floordiv
演算子関数で使用される演算子関数を 2 番目の引数としてインポートしました。ここでのパラメータ値は 3 番目のパラメータである 55 を 0 で割るためのものです。
assert の最後のアプリケーションは、assertRaises()
に予期されたもの以外の別の例外を渡すときです。代わりにエラーが生成されます。
上で使用したのと同じサンプルコードを使用して、これを実装しましょう。
import unittest
class MyTestCase(unittest.TestCase):
def test_division_by_error(self):
import operator
self.assertRaises(TypeError, operator.floordiv, 55, 0)
if __name__ == "__main__":
unittest.main()
出力:
E
======================================================================
ERROR: test_division_by_error (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last): File "c:\Users\Neema\Desktop\Article Requirement Spec and Example
Articles\user.py", line 16, in test_division_by_error
self.assertRaises(TypeError, operator.floordiv, 55, 0)
File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 733, in assertRaises
return context.handle('assertRaises', args, kwargs)
File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 201, in handle
callable_obj(*args, **kwargs)
ZeroDivisionError: integer division or modulo by zero
----------------------------------------------------------------------
Ran 1 test in 0.031s
FAILED (errors=1)
出力から、エラートレースバックが生成されます。数値をゼロで割ると、ZeroDivisionError 例外が発生することが予想されます。代わりに、文字列と整数など、異なるデータ型間で算術演算を実行するときに適用される TypeError 例外を渡します。