Python で assertEqual と assertEquals

Aditya Raj 2023年1月30日
  1. Python の assert 文とは
  2. Python の assertEquals() メソッド
  3. Python の assertEqual() メソッド
  4. まとめ
Python で assertEqual と assertEquals

ソフトウェアを構築する際には、コードを使用してビジネスロジックを実装する必要があります。

すべてのロジックと制約を確実に実装するために、プログラムで assert ステートメントを使用します。大規模なアプリケーションでは、Python の assertEquals() および assertEqual() メソッドを使用して単体テストを使用します。

Python で assert ステートメントがどのように機能するかについて説明します。また、assertEquals() および assertEqual() メソッドを使用して、Python でビジネスロジックと制約を実装する方法についても説明します。

Python の assert 文とは

Python では、assert ステートメントは式が True または False であるかどうかをチェックします。assert ステートメントの構文は次のとおりです。

assert conditional_expression

ここでは、assert がキーワードです。conditional_expression は、ステートメントを True または False として評価する条件付きステートメントです。

condition_expressionTrue と評価された場合、プログラムの実行は次のステートメントに進みます。反対に、conditional_expressionFalse と評価された場合、プログラムは AssertionError 例外を発生させます。

これらすべてを以下で見ることができます。

num1 = 10
num2 = 5
num3 = 10
print("This statement will get printed")
assert num1 == num3
print(
    "This statement will also get printed as the expression in the above assert statement is True."
)
assert num2 == num3
print(
    "This statement will not get printed as the expression in the above assert statement is False. This line of code is unreachable."
)

出力:

This statement will get printed
This statement will also get printed as the expression in the above assert statement is True.

Traceback (most recent call last):
  File "tempy.py", line 9, in <module>
    assert num2 == num3
AssertionError

ここでは、最初の print ステートメントが自動的に実行されることがわかります。

ステートメント assert num1 == num3 は、10==10True と評価されるため、エラーを発生させません。したがって、2 番目の print ステートメントも実行されます。

その後、ステートメント"assert num2 == num3"は、5==10False と評価されるときに AssertionError を発生させます。このため、プログラムの実行は停止し、3 番目の print ステートメントは実行されません。

AssertionError 例外が発生したときにメッセージを表示することもできます。このために、次の構文を使用します。

assert conditional_expression, message

ここで、message は、conditional_expressionFalse と評価され、AssertionError が発生したときに出力される文字列です。これは以下で確認できます。

num1 = 10
num2 = 5
num3 = 10
print("This statement will get printed")
assert num1 == num3, "{} is not equal to {}".format(num1, num2)
print(
    "This statement will also get printed as the expression in the above assert statement is True."
)
assert num2 == num3, "{} is not equal to {}".format(num2, num3)
print(
    "This statement will not get printed as the expression in the above assert statement is False. This line of code is unreachable."
)

出力:

This statement will get printed
This statement will also get printed as the expression in the above assert statement is True.

Traceback (most recent call last):
  File "tempy.py", line 9, in <module>
    assert num2 == num3, "{} is not equal to {}".format(num2, num3)
AssertionError: 5 is not equal to 10

AssertionError を通知した後、出力 5 is not equal to 10 も出力されます。これらのタイプのメッセージを含めると、AssertionError 例外が発生するたびにメッセージを使用して要件を通知できるため、プログラムの機能をより簡単にテストできます。

assert ステートメントを使用して、制約を適用したり、Python でビジネスロジックを実装したりできます。ただし、assert ステートメントを使用することには欠点があります。assert ステートメントの条件ステートメントが False と評価されると、プログラムの実行が停止します。

したがって、何千もの制約と条件を持つ大規模なプログラムでは、AssertionError 例外が発生する回数だけプログラムを実行する必要があります。

これを克服するために、前述のように assertEquals() または assertEqual() ステートメントを使用できます。

Python の assertEquals() メソッド

ソフトウェアに制約とビジネスロジックを適用するために、unittest モジュールを使用できます。

unittest モジュールは、制約を適用するために使用できる多くのメソッドを提供します。同等性のアサーションを実装するには、assertEquals() メソッドと assertEqual() メソッドを使用できます。

assertEquals() メソッドを使用して同等性のアサーションを実装するには、最初に、unittest モジュールで定義された TestCase クラスのサブクラスであるクラスを作成します。次に、assertEquals() メソッドの次の構文を使用して、等式のアサーションを定義できます。

self.assertEquals(self, first, second)

ここで、パラメータ first は最初の値を入力引数として受け入れます。パラメータ second は、入力引数として 2 番目の値を受け入れます。

パラメータ first がパラメータ second の値と等しい場合、単体テストは正常に合格します。それ以外の場合は、現在の行で AssertionError 例外が発生し、ユーザーにエラーが通知されます。

したがって、テストケースは失敗しますが、assert ステートメントの場合のようにプログラムの実行は停止しません。プログラムはすべてのテストケースを実行してから、開発者にすべてのエラーを通知します。

これは以下で確認できます。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        self.assertEquals(self.num1, self.num3)

    def test_condition2(self):
        self.assertEquals(self.num2, self.num3)


if __name__ == "__main__":
    unittest.main()

出力:

/home/aditya1117/PycharmProjects/pythonProject/webscraping.py:14: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(self.num1, self.num3)
.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 17, in test_condition2
    self.assertEquals(self.num2, self.num3)
AssertionError: 5 != 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

ここで、unittest.main() メソッドを実行すると、Tester クラスのインスタンスが作成されます。その後、setUp() メソッドが実行されます。setUp() メソッドは変数を初期化し、他のモジュールからテスタークラスに値をインポートします。

また、メソッド test_condition1() および test_condition2() が実装されていることも確認できます。ここでは、condition1condition2 という名前の前に test_ を含めて、これらのメソッドがテストケースを実施するために使用されていることをインタプリタに理解させています。

test_ で始まるメソッド名を指定しない場合、メソッドは Python インタープリターによって実行されません。

tearDown() メソッドは、すべてのテストケースの後に実行されます。このメソッドを使用して、変数やその他の値を再初期化できます。

すべてのテストケースを実行した後、結果はテストケースが失敗したことを示しています。assertEquals() メソッドが AssertionError 例外を発生させる(つまり、テストケースが失敗する)たびに、オプションのメッセージを出力することもできます。

このため、以下に示すように、メッセージ文字列を 3 番目の入力引数として assertEquals() メソッドに渡す必要があります。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEquals(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEquals(self.num2, self.num3, message)


if __name__ == "__main__":
    unittest.main()

出力:

Test case completed. Result:

Test case completed. Result:
/home/aditya1117/PycharmProjects/pythonProject/webscraping.py:15: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(self.num1, self.num3,message)
.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 19, in test_condition2
    self.assertEquals(self.num2, self.num3,message)
AssertionError: 5 != 10 : 5 is not equal to 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

ここでは、2 番目のテストケースが失敗したときに、インタプリタが 5 は 10 に等しくありませんというメッセージも出力することがわかります。

assertEquals() メソッドは 2010 年に廃止されました。したがって、assertEquals() メソッドを使用しているときに、メソッドが廃止されたという警告が表示され、DeprecationWarning: Please use assertEqual instead というメッセージが表示されます。

Python が assertEqual() メソッドの使用を提案しているので、それを使用して Python で同等性のアサーションを実装しましょう。

Python の assertEqual() メソッド

名前に s が含まれていることを除けば、assertEqual() メソッドの動作は assertEquals() メソッドと完全に似ています。両方のメソッドの構文も同じです。

したがって、次のように、assertEquals() メソッドの代わりに assertEqual() メソッドを使用できます。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        self.assertEqual(self.num1, self.num3)

    def test_condition2(self):
        self.assertEqual(self.num2, self.num3)


if __name__ == "__main__":
    unittest.main()

出力:

.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 17, in test_condition2
    self.assertEqual(self.num2, self.num3)
AssertionError: 5 != 10

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

Process finished with exit code 1

出力では、プログラムが前のコードと同じように機能することがわかります。また、減価償却についての警告は受けていません。

次のように、テストケースにメッセージを追加できます。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEqual(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEqual(self.num2, self.num3, message)


if __name__ == "__main__":
    unittest.main()

出力:

.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 19, in test_condition2
    self.assertEqual(self.num2, self.num3, message)
AssertionError: 5 != 10 : 5 is not equal to 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

この記事では、unittest モジュールで定義された TestCase クラスのサブクラスを実装して、assertEquals() メソッドと assertEqual() メソッドを使用していることを確認できます。

Django フレームワークを使用してプログラムを開発しているときに、Django.test モジュールで定義された TestCase クラスのサブクラスを実装してしまう可能性があります。このような場合、プログラムは以下のようにエラーになります。

import unittest
from django.test import TestCase


class Tester(TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEqual(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEqual(self.num2, self.num3, message)


if __name__ == "__main__":
    unittest.main()

出力:

E
======================================================================
ERROR: setUpClass (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 1201, in setUpClass
    super().setUpClass()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 187, in setUpClass
    cls._add_databases_failures()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 209, in _add_databases_failures
    cls.databases = cls._validate_databases()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 195, in _validate_databases
    if alias not in connections:
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 73, in __iter__
    return iter(self.settings)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 45, in settings
    self._settings = self.configure_settings(self._settings)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/db/utils.py", line 144, in configure_settings
    databases = super().configure_settings(databases)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 50, in configure_settings
    settings = getattr(django_settings, self.settings_name)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/conf/__init__.py", line 84, in __getattr__
    self._setup(name)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/conf/__init__.py", line 65, in _setup
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

----------------------------------------------------------------------
Ran 0 tests in 0.003s

FAILED (errors=1)

ここでは、django.test モジュールの TestCase クラスを使用すると、プログラムでエラーが発生することがわかります。したがって、テストケースは実行されません。

したがって、Django.test モジュールではなく、unittest モジュールで定義された TestCase クラスを常に使用するようにしてください。

まとめ

アプリケーションをテストするために、assert ステートメント、assertEquals()、および assertEqual() メソッドを使用することについて説明しました。

ここで、assert ステートメントと assertEqual() メソッドを実稼働環境の実際のアプリケーションで使用できないことを覚えておくと役に立ちます。これらのメソッドを使用して、本番環境にコードをデプロイする前にアプリケーションをテストすることしかできません。

また、assertEquals() メソッドの代わりに assertEqual() メソッドを使用するようにしてください。後者は Python プログラミング言語で非推奨になっているためです。

著者: Aditya Raj
Aditya Raj avatar Aditya Raj avatar

Aditya Raj is a highly skilled technical professional with a background in IT and business, holding an Integrated B.Tech (IT) and MBA (IT) from the Indian Institute of Information Technology Allahabad. With a solid foundation in data analytics, programming languages (C, Java, Python), and software environments, Aditya has excelled in various roles. He has significant experience as a Technical Content Writer for Python on multiple platforms and has interned in data analytics at Apollo Clinics. His projects demonstrate a keen interest in cutting-edge technology and problem-solving, showcasing his proficiency in areas like data mining and software development. Aditya's achievements include securing a top position in a project demonstration competition and gaining certifications in Python, SQL, and digital marketing fundamentals.

GitHub