『Pythonプログラミング入門から実践へ』Day 14を読む

9664 ワード

第十一章


関数またはクラスを記述する場合は、テストを記述することもできます.テストにより,コードが各種入力に対して要求通りに動作することが決定される.

1、テスト関数


次は、名前と姓を受け入れ、ファイルnameに格納されたきれいな名前を返すテストに使用する関数です.function.py:
def get_formatted_name(first, last):
    full_name = first + ' ' + last
    return full_name.title()

関数は、名前と姓を名前に結合し、名前と姓の間にスペースを追加し、頭文字を大文字にして結果を返します.関数が所望のように動作するかどうかを確認するために、この関数を使用するプログラムを作成します.
from name_function import get_formatted_name

print("Enter 'q' at any time to quit.")
while True:
    first = input("
Please give me a first name: ") if first == 'q': break last = input("Please give me a last name: ") if last == 'q': break formatted_name = get_formatted_name(first, last) print("\tNeatly formatted name: " + formatted_name + ".")

テストは次のとおりです.
Enter 'q' at any time to quit.

Please give me a first name: janis
Please give me a last name: joplin
    Neatly formatted name: Janis Joplin.

Please give me a first name: bob
Please give me a last name: dylan
    Neatly formatted name: Bob Dylan.

Please give me a first name: q

テストの結果から、マージした名前が正しいことがわかります.中間名を扱う機能を追加する必要がある場合は、元の機能を破壊しないことを保証した上で、新しい機能を追加してテストする必要があります.これは煩雑ですが、Pythonは関数の出力を自動的にテストする効率的な方法を提供しており、対応する関数を自動的にテストすることができます.
(1)ユニットテストとテスト用例
Python標準ライブラリのモジュールunittestは、コードテストツールを提供しています.ユニットテストは関数のある側面に問題がないことを確認するために使用されます.テスト例は、様々な状況における関数の挙動が要求に合致することを確認するユニットテストのセットである.良好なテスト例は、これらのすべての状況に対するテストを含む、関数が受信する可能性のある様々な入力を考慮している.フルオーバーライドテストの例は、様々な可能な関数の使用方法をカバーするユニットテストのセットを含む.大規模なプロジェクトでは、フルオーバーライドを実現するのは難しいかもしれません.通常,最初はコードの重要な動作に対してテストを記述すればよいが,プロジェクトが広く使用される場合には全オーバーライドを考慮する.
(2)合格できるテスト
関数のテスト例を作成するには、モジュールunittestとテストする関数をインポートしてからunittestを作成します.TestCaseのクラスは,関数挙動の異なる側面をテストする一連の方法を記述した.次は、1つのメソッドのみを含むテスト例です.
import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

unittest.main()
#  :
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

まず、モジュールunittestとテストする関数をインポートする必要があります.次に、unittestを継承する必要があるテスト関数に対する一連のユニットテストを含むクラスを作成する.TestCaseクラスは、Pythonが作成したテストをどのように実行するかを知っています.このクラスには、名前が正しくフォーマットされているかどうかを確認する方法しか含まれていません.上記のファイルを実行するとtest_ヘッドのメソッドは自動的に実行されます.ここではunittestクラスで最も有用な機能の1つである断言方法を使用します.断言方法は、得られた結果が所望の結果と一致するかどうかを確認するために使用される.self.assertEqual()メソッドは、1番目のパラメータと2番目のパラメータを比較することです.出力の結果、最初の行の句点は、テストに合格したことを示します.次の行はPythonがテストを実行したことを示しており、消費時間は0.001秒未満です.最後のOKは、この試験例のすべてのユニット試験が合格したことを示している.
(3)合格できないテスト
中間名を処理できるパラメータmiddleのみを関数に追加し,テスト例の実パラメータを変更しなかった.実行結果:
E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_name_function.py", line 8, in test_first_last_name
    formatted_name = get_formatted_name('janis', 'joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'

----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (errors=1)

テストに失敗したため、多くの情報が返されました.最初の行の出力は、テスト例のセルテストがエラーを招いたことを示すアルファベットEのみです.クラス内の関数がエラーを引き起こしていることがわかります.テスト例に多くのユニットテストが含まれている場合、そのテストが合格しなかったことを正確に知ることが重要です.下に、関数呼び出しに問題が発生したことを正確に指摘する標準的なtracebackが表示されます.これは、必要不可欠な位置実パラメータが欠けているためです.最後に、ユニットテストが実行されたことを示し、テスト例全体が合格しなかったことを示します.
(4)テストに失敗した場合はどうする
テストが合格しなかったのは、あなたが書いた新しいコードが間違っていることを説明しています.この場合、テストを修正しないで、テストが合格できないコードを修復する必要があります.関数に対する修正をチェックし、関数の動作が予想に合わない修正を見つけます.上記で合格できなかったテストでは,新規の中間名パラメータが原因であることが分かったので,中間名をオプション,すなわちデフォルト値を追加し,if判定文を適切に追加すればテストを合格させることができる.
(5)新規テストの追加
中間名を含む名前をテストするテストをもう1つ作成します.
import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

    def test_first_last_middle_name(self):
        formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
        self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')

unittest.main()
#  :
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

この新しい追加メソッドのメソッド名はtest_でなければなりません.最初は、テストファイル全体を実行するときに自動的に実行されます.TestCaseクラスで長いメソッド名を使用することは可能です.これらのメソッド名は、テストに合格しなかったときの出力を理解するために記述的でなければなりません.これらの方法はPythonによって自動的に呼び出され、呼び出されたコードを書く必要はありません.

2、テストクラス


(1)unittest Moduleでよく使われる6つの断言方法
方法
用途
assertEqual(a, b)
確認a==b
assertNotEqual(a, b)
aを確認!=b
assertTrue(x)
xがTrueであることを確認
assertFalse(x)
xがFalseであることを確認
assertIn(item, list)
リスト内のitemの確認
assertNotIn(item, list)
itemがlistにないことを確認
Pythonはunittestにあります.TestCaseクラスでは多くの断言方法が提供されている.満たすべき条件が実際に満たされていないと思ったら、Pythonは異常を起こします.
(2)テストするクラス
クラスのテストは関数の死と似ているが,いくつかの違いもある.匿名調査の管理を支援するクラスは次のとおりです.
class AnonymousSurvey():
    def __init__(self, question):
        self.question = question
        self.responses = []
    
    def show_question(self):
        print(self.question)
    
    def store_response(self, new_response):
        self.responses.append(new_response)
    
    def show_results(self):
        print("Survey results:")
        for response in self.responses:
            print('- ' + response)

このクラスのインスタンスを作成するには、問題を1つ提供するだけです.次に、使用するプログラムを作成します.
from survey import AnonymousSurvey

question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.show_question()
print("Enter 'q' at any time to quit.
") while True: response = input("Language: ") if response == 'q': break my_survey.store_response(response) print("
Thank you to everyone who participated in the survey!") my_survey.show_results() # : What language did you first learn to speak? Enter 'q' at any time to quit. Language: English Language: Spanish Language: English Language: Mandarin Language: q Thank you to everyone who participated in the survey! Survey results: - English - Spanish - English - Mandarin

(3)AnonymousSurveyクラスのテスト
次のテストを作成します.ユーザーが質問を調査するときに1つの答えしか提供しない場合、この答えも適切に保存できます.
import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    def test_store_single_response(self):
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)

unittest.main()
#  :
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

ここでのテストは関数をテストするときと同様で、ここで最初の方法では、調査問題の単一の答えが格納されていることを検証した後、調査結果リストに含まれます.クラスの動作をテストするには、インスタンスを作成する必要があります.出力から分かるように、テストは無事合格しました.次に、ユーザが3つの答えを提供した場合、それらも適切に格納されることを確認します.
    def test_store_three_responses(self):
        question = "What language did you first learn to speak?"
        my_survey = AnonymousSurvey(question)
        responses = ['English', 'Spanish', 'Mandarih']
        for response in responses:
            my_survey.store_response(response)
            
        for response in responses:
            self.assertIn(response, my_survey.responses)
#  :
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

試験クラスに上記の方法を追加した結果,試験も順調に合格したことが分かった.しかし、これらのテストにはいくつかの重複点があります.次にunittestの別の機能を使用して、効率を向上させます.
(4)メソッドsetUp()
前の例では、各テストメソッドにAnonymousSurveyインスタンスを作成し、各メソッドに答えを作成しました.unittest.TestCaseクラスにはメソッドsetup()が含まれており、Pythonはまずそれを実行し、test_でそれぞれを実行します.冒頭の方法.これにより、作成した各テストメソッドで、メソッドsetup()で作成したオブジェクトを使用できます.次にsetUp()を使用して、2つのテスト方法で使用できる調査対象と回答のセットを作成します.
import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    
    def setUp(self):
        question = "What language did you first learn to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English', 'Spanish', 'Mandarih']
    
    def test_store_single_response(self):
        self.my_survey.store_response(self.responses[0])
        self.assertIn(self.responses[0], self.my_survey.responses)

    def test_store_three_responses(self):
        for response in self.responses:
            self.my_survey.store_response(response)
        for response in self.responses:
            self.assertIn(response, self.my_survey.responses)

unittest.main()

メソッドsetuup()は、2つのことをしました.調査対象を作成します.答えのリストを作成します.この2つのものを格納する変数名には、接頭辞self(すなわち属性に格納される)が含まれているため、このクラスのどこでも使用できます.自分で作成したクラスをテストする場合、メソッドsetUp()は、setUp()メソッドで一連のインスタンスを作成し、プロパティを設定し、テストメソッドで直接使用することができます.
注意:テスト例を実行するとき、ユニットテストが完了するたびに、Pythonは文字を印刷します.テストが合格したときに句点を印刷します.テストエラーが発生したときにEを印刷します.テストによって断言に失敗した場合、Fを印刷します.これが、テスト・インスタンスを実行するときに、出力の最初の行に表示される句点と文字数が異なる理由です.テスト例に多くのユニットテストが含まれている場合、長い時間実行する必要がある場合は、これらの結果を観察することによって、いくつのテストが合格したかを知ることができます.