Pythonユニットテスト(unittest)


テストディレクトリ


プロジェクトの全体的な構造は、「ソフトウェアディレクトリ開発仕様」を参照してください.ここでは、テストディレクトリについて説明します.一般的には、プロジェクトにテストディレクトリを個別に作成します.ディレクトリ名は「tests」です.ディレクトリの場所については、プロジェクト名(プロジェクト名がFooであると仮定)の1次サブディレクトリの下に2次サブディレクトリ「Foo/foo/tests」を作成することをお勧めします.しかし、これは使い勝手が悪いためか、次のようなやり方が多い.しかし、次の例では、この方法でテストディレクトリを作成します.また、テストディレクトリを1つ上のレベルに移動し、プロジェクトの下に「Foo/tests」を直接作成することもできます.参考django、scrapy、flaskはいずれもこのようなやり方です.

テスト関数


タイトルは,テストクラス(class)に対して関数(def)をテストすることを意味する.テストを勉強するには、テストするコードが必要です.次の簡単な関数は、都市名と国名を受信し、「City,Country」というフォーマットの文字列を返します.
# UnitTest/unit_test/utils/city_functions.py
def get_city_info(city, country):
    city_info = "%s, %s" % (city, country)
    return city_info.title()

次に、上記の関数をテストします.

手動テスト


この関数を使用するプログラムを書きます.
# UnitTest/unit_test/test/cities.py
try:
    from unit_test.utils.city_functions import get_city_info
except ModuleNotFoundError:
    import sys
    sys.path.append('../..')
    from unit_test.utils.city_functions import get_city_info

print("Enter 'q' at any time to quit.")
while True:
    city = input("city name: ")
    if city == 'q':
        break
    country = input("country name: ")
    if country == 'q':
        break
    fullname = get_city_info(city, country)
    print("\tcity info:", fullname)

次に実行した結果:
Enter 'q' at any time to quit.
city name: shanghai
country name: china
    city info: Shanghai, China
city name: q

Process finished with exit code 0

以上が手動テストなのか、関数出力を自動的にテストする効率的な方法が必要なのか.get_fullname()は自動テストを行い,この関数にテストした名前を与えた後,正しい結果を返すことができると常に確信する.特に関数を修正する前後にあります.モジュールインポートパスの問題PyCharmは自動的にプロジェクトディレクトリを環境変数に追加し、PyCharmで実行しても問題ありません.しかし、PyCharmではなく単独で実行すると、このディレクトリ構造に問題があり、テストが必要な関数が見つからないはずです.簡単には、テスト例とテストされた関数を同じディレクトリに入れ、from importを変更すると正常に動作します.あるいは、例のように環境変数を手動で追加します.

ユニットテスト-unittest


Python標準ライブラリのモジュールunittestは、コードテストツールを提供しています.
作成テストケース関数作成テストケースは、モジュールunittestおよびテストする関数をインポートしてから、継承unittestを作成する.TestCaseのクラスは,関数挙動の異なる側面をテストする一連の方法を記述した.次は、1つのメソッドのみを含むテスト例です.
# UnitTest/unit_test/test/test_city_functions.py
import unittest
try:
    from unit_test.utils.city_functions import get_city_info
except ModuleNotFoundError:
    import sys
    sys.path.append('../..')
    from unit_test.utils.city_functions import get_city_info

class CitiesTestCase(unittest.TestCase):
    """ city_functions.py"""
    def test_city_country(self):
        city_info = get_city_info('shanghai', 'china')
        self.assertEqual(city_info, 'Shanghai, China')

    def test_New_York(self):
        city_info = get_city_info('new york', 'America')
        self.assertEqual(city_info, 'New York, America')

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

命名されたルールと推奨事項:
  • クラス名は、任意に名前を付けることができますが、テストに関連しているように見え、Testの文字が含まれていることが望ましいです.
  • メソッド名、名前は「test_」でなければなりません先頭に「test_」冒頭の方法では、
  • が自動的に実行されます.
    テストの方法の最後にunittestクラスで最も有用な機能の一つである断言方法を使用した.結果が私たちが予想した結果と一致しているかどうかを確認します.出力された効果の最後の行unittest.main()は、Pythonにこのファイルのテストを実行させます.プログラムを実行すると、次のような出力が得られます.
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK

    テストケースを実行すると、ユニットテストが完了するたびに、Pythonに文字が印刷されます.
  • テストが合格したときに1つの句点を印刷します.
  • テストエラーが発生したときにEを印刷します.
  • テストで断言に失敗した場合にFを印刷します.

  • これが、テスト・インスタンスを実行するときに、出力の最初の行に表示される句点と文字数が異なる理由です.テスト例に多くのユニットテストが含まれている場合、長い時間実行する必要がある場合は、これらの結果を観察することによって、いくつのテストが合格したかを知ることができます.
    PyCharmはユニットテストに独自の最適化を行い、出力は上の点が見えず、よりきれいな展示方法があります.

    テストに失敗しました


    テストに合格しない効果を見てみましょう.ここではテスト例を修正するのではなくget_city_info()関数はupdateを作成し、都市の人口数を表示します.
    def get_city_info(city, country, population):
        city_info = "%s, %s -  : %d" % (city, country, population)
        return city_info.title()

    今回はテスト例を再実行し、以下のように出力します.
    E
    ======================================================================
    ERROR: test_city_country (__main__.CitiesTestCase)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "test_city_functions.py", line 17, in test_city_country
        city_info = get_city_info('shanghai', 'china')
    TypeError: get_city_info() missing 1 required positional argument: 'population'
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    FAILED (errors=1)

    ここで見たのは前の点ではなくEで、間違いがあることを示しています.
    テストに失敗した処理ここでは、前のテスト例を修正しないでください.update以前の関数がプロジェクト内で使用されていたと仮定し、テストに合格せず、この関数を呼び出したコードに問題があることを示します.プロジェクトの他のコードを変更したくない場合は、ここでget_を変更してみましょう.city_info()関数は、テストに合格したり、新しい機能を追加したりすることができます.
    # UnitTest/unit_test/utils/city_functions.py
    def get_city_info(city, country, population=None):
        if population:
            city_info = "%s, %s -  : %d" % (city, country, population)
        else:
            city_info = "%s, %s" % (city, country)
        return city_info.title()

    現在の各バージョンのupdateこそ古いバージョンと互換性のあるコードであり、今回のテスト例では合格することができます.
    新しいテストを追加する前のテスト用例は検証できる機能しかありません.今新しい機能が追加されました.問題がないかどうかは、テストを通じて検証する必要があります.
    # UnitTest/unit_test/test/test_city_functions.py
    class CitiesTestCase(unittest.TestCase):
        """ city_functions.py"""
        def test_city_country(self):
            city_info = get_city_info('shanghai', 'china')
            self.assertEqual(city_info, 'Shanghai, China')
    
        def test_New_York_population(self):
            city_info = get_city_info('new york', 'America', 8537673)
            self.assertEqual(city_info, 'New York, America -  : 8537673')

    現在、新機能のテスト例も使用され、2つのテストに合格しています.後でget_をcity_info()関数を変更し、テストを再実行すれば、新しいコードが既存のプロジェクトに影響を及ぼすかどうかを知ることができます.

    アサーションメソッド


    モジュールはunittestです.TestCaseクラスでは多くの断言方法が提供されており,以前は1つ使用していた.次の6つの一般的な断言方法を示します.
  • assertEqual(a,b):a==b
  • を確認する
  • assertNotEqual(a,b):aを確認!=b
  • assertTrue(x):xがTrueであることを確認する
  • assertFalse(x):xがFalseであることを確認する
  • assertIn(item,list):listにおけるitemの
  • の確認
  • assertNotIn(item,list):itemがlistにないことを確認する
  • あなたはunittestを継承するしかありません.TestCaseのクラスではこれらのメソッドが使用されます.

    テストクラス


    前の内容は関数をテストするだけです.クラスが正常に動作することを証明する必要があるため、クラスが使用されることが多い.クラスのテストは関数のテストと似ています.ほとんどの作業はクラス内のメソッドをテストする行為ですが、いくつかの違いがあります.

    テストするクラスの準備


    まず、クラスを作成してテストします.このクラスには、カリキュラム名と、そのカリキュラムを学習する学習者が格納されています.
    # UnitTest/unit_test/course.py
    class CourseManage(object):
    
        def __init__(self, course):
            self.course = course
            self.students = []
    
        def show_course(self):
            print(" :", self.course)
    
        def add_student(self, name):
            self.students.append(name)
    
        def show_students(self):
            print(" :")
            for student in self.students:
                print('-', student)

    CourseManagementクラスが正常に動作していることを証明するために、使用するプログラムをもう1つ作成します.
    from unit_test.course import CourseManage
    
    course = CourseManage("Python")
    course.show_course()
    print(" ...")
    print("Enter 'q' at any time to quit.
    ") while True: resp = input("Student's Name: ") if resp == 'q': break if resp: course.add_student(resp.title()) print("
    ...") course.show_students()

    このプログラムは、カリキュラムを定義し、カリキュラム名を使用してCourseManagementオブジェクトを作成します.次に、主に呼び出しオブジェクトのadd_student()メソッドは、学習者の名前を入力します.入力が完了したら、qを押して終了できます.最後にすべての学習者が印刷されます.すべての入力と出力は次のとおりです.
     : Python
     ...
    Enter 'q' at any time to quit.
    
    Student's Name: oliver queen
    Student's Name: barry allen
    Student's Name: kara
    Student's Name: sara lance
    Student's Name: q
    
     ...
     :
    - Oliver Queen
    - Barry Allen
    - Kara
    - Sara Lance
    
    Process finished with exit code 0

    クラスのテスト例の作成


    次に、CourseManagementクラスの動作の一態様を検証するテストを作成します.ユーザが学習者の名前を入力場合、この名前はselfに格納することができる.studentsのリストにあります.したがって、学習者が入力された後、assertIn()という断言方法を使用する必要があります.
    # UnitTest/unit_test/test/test_course.py
    import unittest
    from unit_test.course import CourseManage
    
    class TestCourseManage(unittest.TestCase):
    
        def test_add_student(self):
            course = CourseManage("Python")
            name = 'snart'
            course.add_student(name.title())
            self.assertIn('Snart', course.students)
    
    if __name__ == '__main__':
        unittest.main()

    上記の方法では、1人の学習者を入力する場合のみ検証されていますが、多くの場合、多くの学習者がいます.また、複数の学習者が正常に入力されているかどうかを確認する方法を追加します.
    class TestCourseManage(unittest.TestCase):
    
        def test_add_student(self):
            course = CourseManage("Python")
            name = 'snart'
            course.add_student(name.title())
            self.assertIn('Snart', course.students)
    
        def test_add_students(self):
            course = CourseManage("Python")
            name_list = ['oliver queen', 'barry allen', 'kara', 'sara lance']
            for name in name_list:
                course.add_student(name.title())
            for name in name_list:
                self.assertIn(name.title(), course.students)

    setUp()メソッド


    上記の例では、各テストメソッドにインスタンスが作成されています.しかし、もう1つの要件は、インスタンスを1つだけ作成することですが、このインスタンスを複数の方法で操作して繰り返し検証することです.unittestでTestCaseクラスにはメソッドsetup()が含まれており、一度だけインスタンス化でき、各テストメソッドで使用できます.TestCaseクラスにメソッドsetup()が含まれている場合、Pythonはまずそれを実行し、test_でそれぞれを実行します.頭の打ち方.簡単に言えば、setUp()メソッドは親に予約されたフックであり、他のテストメソッドが実行される前に実行されます.
    import unittest
    from unit_test.course import CourseManage
    
    class TestCourseManage(unittest.TestCase):
    
        def setUp(self):
            self.course = CourseManage("Python")
            self.name_list = ['oliver queen', 'barry allen', 'kara', 'sara lance']
    
        def test_add_student(self):
            name = 'snart'
            self.course.add_student(name.title())
            self.assertIn('Snart', self.course.students)
    
        def test_add_students(self):
            for name in self.name_list:
                self.course.add_student(name.title())
            for name in self.name_list:
                self.assertIn(name.title(), self.course.students)
    
    if __name__ == '__main__':
        unittest.main()

    自分で作成したクラスをテストするときにsetup()メソッドを使用すると、テストメソッドの作成が容易になります.setup()メソッドで一連のインスタンスを作成し、プロパティを設定し、テストメソッドで直接使用することをお勧めします.これは、各テストメソッドでインスタンスを作成し、プロパティを設定するよりも簡単です.

    小結


    プロジェクトに初歩的なテストが含まれている場合は、他のプログラマーがあなたを敬服し、あなたが作成したコードをより上手に使用したり、プロジェクトを開発したりすることができます.他のプログラマーが開発したプロジェクトとコードを共有する場合は、作成したコードが既存のテストに合格したことを証明する必要があります.通常、追加した新しい動作のテストを作成する必要があります.コードテストプロセスを熟知するために、多くのテストを展開してください.自分で作成した関数とクラスについては、その重要な動作に対するテストを作成してください.しかし、プロジェクトの初期には、十分な理由がない限り、オーバーライドされたテスト例を作成しようとしないでください.

    pytest


    この記事はPythonに内蔵されているユニットテストモジュールです.初心者としては慣れるといいですね.pytestはPythonの最も流れの単一測定フレームワークの一つである.具体的にはGitHubが参考にしてオープンソースプロジェクトのユニットテストを行うことができ、多くの場合これを使用しています.