4 Pythonコマンドライン(CLI)アプリをテストするためのテクニック

4 Pythonコマンドライン(CLI)アプリをテストするためのテクニック

最初のPythonコマンドラインアプリの構築が完了しました。 または、2番目または3番目かもしれません。 しばらくの間Pythonを学習してきましたが、これでhttps://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/[何か大きく複雑なものを構築する準備ができました]、ただしコマンドラインで実行可能です。 または、https://realpython.com/python-testing/[build and testing] WebアプリケーションまたはGUIを使用したデスクトップアプリケーションに慣れていますが、現在はCLIアプリケーションの構築を開始しています。

これらのすべての状況において、Python CLIアプリケーションをテストするためのさまざまな方法を学び、慣れる必要があります。

ツールの選択は恐ろしいかもしれませんが、覚えておくべき主なことは、コードが生成する出力と期待する出力を比較しているだけです。 それからすべてが続きます。

このチュートリアルでは、Pythonコマンドラインアプリをテストするための4つの実践的なテクニックを学習します。

  • `+ print()+`による「Lo-Fi」デバッグ

  • 視覚的なPythonデバッガーの使用

  • pytestとモックを使用した単体テスト

  • 統合テスト

無料ボーナス: link:#[ここをクリックしてPythonテストに関するチートシートを入手してください]。このチュートリアルで説明するテクニックをまとめています。

すべては、マルチレベル辞書の形式でデータを何らかの方法で変換する2つの関数に渡し、ユーザーに出力する基本的なPython CLIアプリを中心に構築されます。

以下のコードを使用して、テストに役立ついくつかの異なる方法を調べます。 確かに網羅的ではありませんが、このチュートリアルが、主要なテストドメインで効果的なテストを作成する自信を得るのに十分な幅を与えることを願っています。

この初期コードにいくつかのバグを振りかけました。これらのバグはテストメソッドで公開します。

_ :簡単にするために、このコードには、辞書内のキーの存在を確認するなど、基本的なベストプラクティスは含まれていません。 _

最初のステップとして、このアプリケーションのすべての段階でオブジェクトについて考えてみましょう。 John Qを記述する構造から始めます。 パブリック:

JOHN_DATA = {
    'name': 'John Q. Public',
    'street': '123 Main St.',
    'city': 'Anytown',
    'state': 'FL',
    'zip': 99999,
    'relationships': {
        'siblings': ['Michael R. Public', 'Suzy Q. Public'],
        'parents': ['John Q. Public Sr.', 'Mary S. Public'],
    }
}

次に、他の辞書をフラット化します。最初の変換関数 `+ initial_transform +`を呼び出した後にこれを期待します。

JOHN_DATA = {
    'name': 'John Q. Public',
    'street': '123 Main St.',
    'city': 'Anytown',
    'state': 'FL',
    'zip': 99999,
    'siblings': ['Michael R. Public', 'Suzy Q. Public'],
    'parents': ['John Q. Public Sr.', 'Mary S. Public'],
}

次に、関数 `+ final_transform +`を使用して、すべての住所情報を単一の住所エントリに構築します。

JOHN_DATA = {
    'name': 'John Q. Public',
    'address': '123 Main St. \nAnytown, FL 99999'
    'siblings': ['Michael R. Public', 'Suzy Q. Public'],
    'parents': ['John Q. Public Sr.', 'Mary S. Public'],
}

そして、 `+ print_person +`の呼び出しはこれをコンソールに書き込みます:

Hello, my name is John Q. Public, my siblings are Michael R. Public
and Suzy Q. Public, my parents are John Q. Public Sr. and Mary S. Public,
and my mailing address is:
123 Main St.
Anytown, FL 99999

testapp.py:

def initial_transform(data):
    """
    Flatten nested dicts
    """
    for item in list(data):
        if type(item) is dict:
            for key in item:
                data[key] = item[key]

    return data


def final_transform(transformed_data):
    """
    Transform address structures into a single structure
    """
    transformed_data['address'] = str.format(
        "{0}\n{1}, {2} {3}", transformed_data['street'],
        transformed_data['state'], transformed_data['city'],
        transformed_data['zip'])

    return transformed_data


def print_person(person_data):
    parents = "and".join(person_data['parents'])
    siblings = "and".join(person_data['siblings'])
    person_string = str.format(
        "Hello, my name is {0}, my siblings are {1}, "
        "my parents are {2}, and my mailing"
        "address is: \n{3}", person_data['name'],
        parents, siblings, person_data['address'])
    print(person_string)


john_data = {
    'name': 'John Q. Public',
    'street': '123 Main St.',
    'city': 'Anytown',
    'state': 'FL',
    'zip': 99999,
    'relationships': {
        'siblings': ['Michael R. Public', 'Suzy Q. Public'],
        'parents': ['John Q. Public Sr.', 'Mary S. Public'],
    }
}

suzy_data = {
    'name': 'Suzy Q. Public',
    'street': '456 Broadway',
    'apt': '333',
    'city': 'Miami',
    'state': 'FL',
    'zip': 33333,
    'relationships': {
        'siblings': ['John Q. Public', 'Michael R. Public',
                    'Thomas Z. Public'],
        'parents': ['John Q. Public Sr.', 'Mary S. Public'],
    }
}

inputs = [john_data, suzy_data]

for input_structure in inputs:
    initial_transformed = initial_transform(input_structure)
    final_transformed = final_transform(initial_transformed)
    print_person(final_transformed)

現時点では、コードは実際にこれらの期待を満たしていないため、それらについて学習しながら4つの手法を使用して調査します。 これを行うことにより、これらの技術の使用に関する実践的な経験を獲得し、快適な領域をそれらに拡張し、どの問題に最も適しているかを学び始めます。

印刷による「Lo-Fi」デバッグ

これは最も簡単なテスト方法の1つです。 ここで必要なのは、関数呼び出しの前、関数呼び出しの後、または関数内で、関心のある変数またはオブジェクトである「+ print +」です。

それぞれ、関数の入力、関数の出力、および関数のロジックを検証できます。

上記のコードを「+ testapp.py 」として保存し、「 python testapp.py +」で実行しようとすると、次のようなエラーが表示されます。

Traceback (most recent call last):
  File "testapp.py", line 60, in <module>
    print_person(final_transformed)
  File "testapp.py", line 23, in print_person
    parents = "and".join(person_data['parents'])
KeyError: 'parents'

`+ print_person `に渡される ` person_data `にキーがありません。 最初のステップは、「 print_person 」への入力を確認し、予想される出力(印刷されたメッセージ)が生成されない理由を確認することです。 ` print_person `の呼び出しの前に、 ` print +`関数呼び出しを追加します。

final_transformed = final_transform(initial_transformed)
print(final_transformed)
print_person(final_transformed)

ここでは、「+ print 」関数がジョブを実行し、最上位の「 parents 」キーも「 siblings 」キーも持っていないことを出力に示しますが、私たちの健全性のために、マルチレベルオブジェクトをより読みやすい方法で印刷する ` pprint `を表示します。 それを使用するには、スクリプトの先頭に「 from pprint import pprint +」を追加します。

`+ print(final_transformed)`の代わりに、 ` pprint(final_transformed)+`を呼び出してオブジェクトを検査します。

{'address': '123 Main St.\nFL, Anytown 99999',
 'city': 'Anytown',
 'name': 'John Q. Public',
 'relationships': {'parents': ['John Q. Public Sr.', 'Mary S. Public'],
                   'siblings': ['Michael R. Public', 'Suzy Q. Public']},
 'state': 'FL',
 'street': '123 Main St.',
 'zip': 99999}

これを上記の予想最終フォームと比較してください。

`+ final_transform `が ` relationships `辞書に触れないことがわかっているので、 ` initial_transform +`で何が起こっているのかを見てみましょう。 通常、従来のデバッガーを使用してこの手順を実行しますが、印刷デバッグの別の使用方法を示したいと思います。

オブジェクトの状態をコードで印刷できますが、それに限定されません。 好きなものを印刷できるので、マーカーを印刷して、どの論理分岐がいつ実行されたかを確認することもできます。

`+ initial_transform +`は主に少数のループであり、内部ディクショナリは内部forループによって処理されることになっているため、そこで発生していることを確認する必要があります。

def initial_transform(data):
    """
    Flatten nested dicts
    """
    for item in list(data):
        if type(item) is dict:
            print "item is dict!"
            pprint(item)
            for key in item:
                data[key] = item[key]

    return data

入力 `+ data +`内で辞書に出くわすと、コンソールで警告され、アイテムがどのように見えるかがわかります。

実行後、コンソール出力は変更されていません。 これは、「+ if +」ステートメントが期待どおりに機能しないことを示す良い証拠です。 バグを見つけるために印刷を続けることができますが、これはデバッガーを使用することの長所を示す素晴らしい方法です。

ただし、演​​習として、印刷デバッグのみを使用してこのコードをバグ追跡することをお勧めします。 これは良い習慣であり、コンソールを使用してコードで発生しているさまざまなことについて警告するためのすべての方法を考えるように強制します。

要約

印刷デバッグを使用する場合:

  • 単純なオブジェクト

  • より短いスクリプト

  • 一見単純なバグ

  • 素早い検査

    *さらに深く
  • pprint-印刷オブジェクトをきれいにする

長所:

  • 迅速なテスト

  • 使いやすい

短所:

  • ほとんどの場合、プログラム全体を実行する必要があります。それ以外の場合:

  • フローを手動で制御するには、追加のコードを追加する必要があります

  • 特に複雑なコードでは、完了時にテストコードを誤って残すことができます

デバッガーを使用する

デバッガーは、一度に1行ずつコードをステップ実行し、アプリケーション全体の状態を検査する場合に最適です。 エラーが発生している場所を大まかに知っている場合に役立ちますが、理由を把握することはできません。また、アプリケーション内で発生しているすべてをすぐに見渡すことができます。

そこには多くのデバッガがあり、多くの場合、IDEに付属しています。 Pythonにはhttps://realpython.com/python-debugging-pdb/[`+ pdb +`と呼ばれるモジュール]もあり、https://realpython.com/interacting-with-python/[REPL]で使用できます。デバッグコード。 使用可能なすべてのデバッガーの実装固有の詳細に入るのではなく、このセクションでは、_breakpoints_や_watches_の設定などの一般的な機能でデバッガーを使用する方法を示します。

*ブレークポイント*は、アプリケーションの状態を検査するために実行を一時停止する場所をデバッガーに指示するコード上のマーカーです。 *ウォッチ*は、デバッグセッション中に変数の値(およびそれ以上)を監視するために追加できる式であり、アプリの実行を通じて保持されます。

しかし、ブレークポイントに戻りましょう。 これらは、デバッグセッションを開始または継続する場所に追加されます。 `+ initial_transform `メソッドをデバッグしているので、そこに配置したいでしょう。 `(*)+`でブレークポイントを示します:

def initial_transform(data):
    """
    Flatten nested dicts
    """
(*) for item in list(data):
        if type(item) is dict:
            for key in item:
                data[key] = item[key]

    return data

デバッグを開始すると、その行で実行が一時停止し、プログラム実行の特定のポイントで変数とその型を確認できます。 コードをナビゲートするいくつかのオプションがあります。stepover _、 step in_、および_step out_が最も一般的です。

_Step over_は、最も頻繁に使用するものです。これは、次のコード行にジャンプするだけです。

ステップイン、コードをさらに掘り下げます。 これは、より深く調査したい関数呼び出しに出会ったときに使用します。その関数のコードに直接移動し、そこで状態を調べることができます。 _step over_と混同する場合にもよく使用します。 幸いなことに、_step out_で私たちを救うことができます。これにより、呼び出し元に戻ることができます。

ここで_watch_を設定することもできます。これは、 `+ type(item)is dict `のようなものです。これは、デバッグセッション中に「ウォッチを追加」ボタンを使用してほとんどのIDEで実行できます。 これで、コードのどこにいても、 ` True `または ` False +`が表示されます。

時計を設定し、ステップオーバーして、 + if type(item)is dict:+`行で一時停止するようにします。 これで、ウォッチのステータス、新しい変数 `+ item +、オブジェクト `+ data +`を確認できるはずです。

Python Debuggerスクリーンショット:変数の監視、width = 2802、height = 550

時計がなくても問題を確認できます。「+ type 」が指すものを見るのではなく、「 item 」が文字列である「 item +」の種類を見るのです。 結局のところ、コンピューターは*正確に*言っていることをします。 デバッガーのおかげで、私たちは方法のエラーを見つけ、次のようにコードを修正します。

def initial_transform(data):
    """
    Flatten nested dicts
    """
    for item in list(data):
        if type(data[item]) is dict:
            for key in data[item]:
                data[key] = item[key]

    return data

デバッガーで再度実行し、コードが期待どおりに動作していることを確認する必要があります。 そして、私たちはそうではありません。構造は次のようになります。

john_data = {
    'name': 'John Q. Public',
    'street': '123 Main St.',
    'city': 'Anytown',
    'state': 'FL',
    'zip': 99999,
    'relationships': {
        'siblings': ['Michael R. Public', 'Suzy Q. Public'],
        'parents': ['John Q. Public Sr.', 'Mary S. Public'],
    },
    'siblings',
    'parents',
}

ビジュアルデバッガーの使用方法を確認したので、次の演習を完了して、さらに深く、新しい知識をテストに加えましょう。

ビジュアルデバッガーについて説明しました。 ビジュアルデバッガーを使用しました。 ビジュアルデバッガが大好きです。 ただし、この手法にはまだ長所と短所があり、以下のセクションでそれらを確認できます。

要約

  • Pythonデバッガーを使用する場合:*

  • より複雑なプロジェクト

  • バグを検出するのが難しい

  • 複数のオブジェクトを検査する必要があります

  • エラーが発生している_where_の大まかな考えがありますが、それに焦点を合わせる必要があります

    *さらに深く
  • 条件付きブレークポイント

  • デバッグ中の式の評価

長所:

  • プログラムの流れを制御する

  • アプリケーションの状態の鳥瞰図

  • バグの発生場所を正確に知る必要はありません

短所:

  • 非常に大きなオブジェクトを手動で見るのが難しい

  • 長時間実行されるコードはデバッグに非常に時間がかかります

PytestとMocksを使用した単体テスト

以前の手法は退屈であり、入出力の組み合わせを徹底的にテストする場合はコードの変更が必要になる可能性があり、特にアプリの成長に合わせてコードのすべてのブランチをヒットします。 この例では、 `+ initial_transform +`の出力はまだ完全に正しく見えません。

コードのロジックは非常にシンプルですが、サイズや複雑さが簡単に増大したり、チーム全体の責任になったりする可能性があります。 より構造化された、詳細な、自動化された方法でアプリケーションをテストするにはどうすればよいですか?

単体テストを入力します。

ユニットテストは、ソースコードを認識可能なユニット(通常はメソッドまたは関数)に分解し、個別にテストするテスト手法です。

基本的に、異なる入力で各メソッドをテストするスクリプトまたはスクリプトのグループを作成して、各メソッド内のすべてのロジックブランチがテストされるようにします。これはコードカバレッジと呼ばれ、通常は100%のコードカバレッジを目指します。 これは必ずしも必要または実用的とは限りませんが、別の記事(または教科書)に保存できます。

各テストは、テスト対象のメソッドを個別に扱います。外部呼び出しは、モッキングと呼ばれる手法でオーバーライドされ、信頼できる戻り値と、テスト後にテストが削除される前に設定されたオブジェクトを提供します。 これらの手法およびその他の手法は、テスト対象のユニットの独立性と分離を保証するために行われます。

期待される出力を実際の出力と比較するというテーマを引き続き継続しているにもかかわらず、再現性と分離はこれらの種類のテストの鍵となります。 ユニットテスト全体を理解したので、簡単に迂回してhttps://realpython.com/the-minimum-viable-test-suite/[最小限の実行可能なテストスイートでFlaskアプリケーションをユニットテストする方法を確認できます。 ]。

パイテスト

理論を深く掘り下げたので、実際にどのように機能するか見てみましょう。 Pythonには `+ unittest `モジュールが組み込まれていますが、 ` pytest `は ` unittest +`が提供するものを構築する上で素晴らしい仕事をすると考えています。 いずれにせよ、単体テストだけで複数の長い記事を取り上げることがあるため、単体テストの基本を示します。

一般的な規則は、すべてのテストをプロジェクト内の `+ test `ディレクトリに配置することです。 これは小さなスクリプトであるため、「 testapp.py 」と同じレベルのファイル「 test_testapp.py +」で十分です。

`+ initial_transform `の単体テストを作成して、予想される入力と出力のセットを設定し、それらが一致することを確認する方法を示します。 私が ` pytest +`で使用する基本的なパターンは、いくつかのパラメーターを取得し、それらを使用してテスト入力を生成するhttps://docs.pytest.org/en/latest/fixture.html[fixture]をセットアップすることです。欲しい出力。

最初にフィクスチャのセットアップを示し、コードを見ているときに、 `+ initial_transform +`のすべての可能なブランチをヒットするために必要なテストケースについて考えます。

import pytest
import testapp as app

@pytest.fixture(params=['nodict', 'dict'])
def generate_initial_transform_parameters(request):

入力を生成する前に、混乱を招く可能性があるため、ここで何が起こっているのか見てみましょう。

まず、 `+ @ pytest.fixture `デコレータを使用して、次の関数定義をフィクスチャとして宣言します。 また、名前付きパラメーター ` params `を使用して、 ` generate_initial_transform_parameters +`とともに使用します。

これのすばらしい機能は、装飾された関数が使用されるたびに、すべてのパラメーターで使用されるため、 + generate_initial_transform_parameters +`を呼び出すだけで、パラメーターとして `+ nodict +`で1回、 `+ dict +で1回

これらのパラメーターにアクセスするには、関数シグネチャにpytest特殊オブジェクト `+ request +`を追加します。

次に、入力と期待される出力を作成しましょう。

@pytest.fixture(params=['nodict', 'dict'])
def generate_initial_transform_parameters(request):
    test_input = {
        'name': 'John Q. Public',
        'street': '123 Main St.',
        'city': 'Anytown',
        'state': 'FL',
        'zip': 99999,
    }
    expected_output = {
        'name': 'John Q. Public',
        'street': '123 Main St.',
        'city': 'Anytown',
        'state': 'FL',
        'zip': 99999,
    }

    if request.param == 'dict':
        test_input['relastionships'] = {
            'siblings': ['Michael R. Public', 'Suzy Q. Public'],
            'parents': ['John Q. Public Sr.', 'Mary S. Public'],
        }
        expected_output['siblings'] = ['Michael R. Public', 'Suzy Q. Public']
        expected_output['parents'] = ['John Q. Public Sr.', 'Mary S. Public']

    return test_input, expected_output

ここで驚くべきことは何もありません。入力と期待される出力を設定し、「+ 'dict' 」パラメーターがある場合は、入力と期待される出力を変更して、「 if +」ブロックをテストします。

次に、テストを作成します。 テストでは、フィクスチャにアクセスするためのパラメータとしてフィクスチャをテスト関数に渡す必要があります。

def test_initial_transform(generate_initial_transform_parameters):
    test_input = generate_initial_transform_parameters[0]
    expected_output = generate_initial_transform_parameters[1]
    assert app.initial_transform(test_input) == expected_output

テスト関数の先頭には + test_ +`を付け、https://dbader.org/blog/python-assert-tutorial [+ assert `ステートメント]に基づいている必要があります。 ここでは、実際の関数に入力を渡すことで得られる出力が、期待される出力に等しいと断言しています。 IDEでテスト構成を使用するか、CLIで「 pytest +」を使用してこれを実行すると、エラーが発生します! 出力はまだ完全ではありません。 次の演習を使用して修正しましょう。実際の経験は非常に貴重であり、読んだ内容を実践に役立てることで、今後思い出しやすくなります。

モック

モックは、単体テストのもう1つの重要な部分です。 単一のコードユニットのみをテストしているため、他の関数呼び出しが何をするかはあまり気にしません。 私たちは彼らから信頼できるリターンを得たいだけです。

外部関数呼び出しを `+ initial_transform +`に追加しましょう:

def initial_transform(data):
    """
    Flatten nested dicts
    """
    for item in list(data):
        if type(data[item]) is dict:
            for key in data[item]:
                data[key] = data[item][key]
            data.pop(item)

    outside_module.do_something()
    return data

`+ do_something()+`をライブで呼び出したくないので、代わりにテストスクリプトでモックを作成します。 モックはこの呼び出しをキャッチし、モックを返すように設定したものを返します。 フィクスチャにモックをセットアップするのが好きです。これはテストセットアップの一部であり、セットアップコードをすべてまとめることができるからです。

@pytest.fixture(params=['nodict', 'dict'])
def generate_initial_transform_parameters(request, mocker):
    [...]
    mocker.patch.object(outside_module, 'do_something')
    mocker.do_something.return_value(1)
    [...]

これで、 `+ initial_transform `を呼び出すたびに、 ` do_something +`呼び出しがインターセプトされ、1が返されます。 フィクスチャパラメータを利用して、モックが返すものを決定することもできます。これは、外部呼び出しの結果によってコードブランチが決定される場合に重要です。

最後の巧妙なトリックは、 `+ side_effect +`を使用することです。 とりわけ、これにより、同じ関数への連続した呼び出しに対して異なるリターンをモックできます。

def initial_transform(data):
    """
    Flatten nested dicts
    """
    for item in list(data):
        if type(data[item]) is dict:
            for key in data[item]:
                data[key] = data[item][key]
            data.pop(item)

    outside_module.do_something()
    outside_module.do_something()
    return data

そのようにモックを設定し、(連続した呼び出しごとの)出力のリストを `+ side_effect +`に渡します:

@pytest.fixture(params=['nodict', 'dict'])
def generate_initial_transform_parameters(request, mocker):
    [...]
    mocker.patch.object(outside_module, 'do_something')
    mocker.do_something.side_effect([1, 2])
    [...]

モックは非常に強力であるため、https://realpython.com/testing-third-party-apis-with-mock-servers/[モックサーバーをセットアップしてサードパーティAPIをテストすることもできます]をお勧めします。 `+ mocker +`を使って自分でモックを掘り下げてください。

要約

  • Pythonユニットテストフレームワークを使用する場合:*

  • 大規模で複雑なプロジェクト

  • OSSプロジェクト

役立つツール:

  • Pytestフィクスチャ

  • 複雑なオブジェクトを比較するためのhttps://pypi.python.org/pypi/deepdiff[deepdiff]

  • モッカー

長所:

  • 実行中のテストを自動化する

  • 多くの種類のバグをキャッチできます

  • チーム向けの簡単なセットアップと変更

短所:

  • 書くのが面倒

  • ほとんどのコード変更で更新する必要があります

  • 実行中の真のアプリケーションを複製しません

統合テスト

統合テストは、ここでは簡単なテスト方法の1つですが、おそらく最も重要なテスト方法の1つです。 これには、実稼働環境のような環境で実際のデータを使用してアプリをエンドツーエンドで実際に実行する必要があります。

これがホームマシン、本番サーバーを複製するテストサーバー、または本番サーバーからテストデータベースへの接続を変更するだけであっても、展開時に変更が機能することを確認できます。

他のすべての方法と同様に、入力が与えられるとアプリケーションが期待される出力を生成することを確認します。ただし、今回は実際の外部モジュールを使用します(ユニットテストではモックされます)。ファイル、および大規模なアプリケーションでは、コードがシステム全体と適切に統合されるようにします。

これを行う方法はアプリケーションに大きく依存します。たとえば、テストアプリは `+ python testapp.py +`で単独で実行できます。 ただし、コードがETLパイプラインのような大規模な分散アプリケーションの一部であるとします。その場合は、コードを交換した状態でテストサーバーでシステム全体を実行し、データを実行し、作成したことを確認する必要があります正しい形式でシステム全体を通過します。 コマンドラインアプリケーションの世界以外では、https://realpython.com/integration-testing-with-pyvows-and-django/[pyVowsはDjangoアプリの統合テストに使用できます]のようなツールです。

要約

  • Pythonで統合テストを使用する場合:*

  • 常に;-)

  • 一般に、他のテスト方法が採用されている場合は、それらの方法の後。

役立つツール:

  • tox環境およびテスト自動化管理

長所:

  • アプリケーションが実際の状況でどのように実行されるかを確認する

短所:

  • 大規模なアプリケーションでは、データフローを正確に追跡するのが難しい場合があります

  • 実稼働環境に非常に近いテスト環境が必要

すべてを一緒に入れて

結論として、すべてのCLIテストは、入力のセットを前提として、予想される出力と実際の出力を比較することです。 上記で説明した方法は、それを行うすべての方法であり、多くの点で補完的です。 これらは、Pythonでコマンドラインアプリケーションを構築し続けるときに理解するための重要なツールになりますが、このチュートリアルは出発点にすぎません。

Pythonには非常に豊富なエコシステムがあり、それはテストツールと方法論にまで及ぶので、これから分岐してさらに調査します。ここで言及しなかったツールやテクニックが見つかるかもしれません。 もしそうなら、コメントでそれを聞きたいです!

簡単に要約すると、今日私たちが学んだテクニックとその使用方法は次のとおりです。

  • デバッグの印刷-コード内の変数やその他のマーカーを印刷して、実行の流れを確認します

  • デバッガー-プログラムの実行を制御して、アプリケーションの状態とプログラムフローの概観を取得します

  • ユニットテスト-アプリケーションを個別にテスト可能なユニットに分割し、そのユニット内のすべてのロジックブランチをテストする

  • 統合テスト-幅広いアプリケーションのコンテキストでコードの変更をテストする

さあ、テストに行きましょう! これらの手法を使用する際には、コメントの中で、どのようにそれらを使用し、どれがお気に入りであるかをお知らせください。

このチュートリアルで示したテクニックを要約したPythonテストのチートシートを入手するには、以下のリンクをクリックしてください。

無料ボーナス: link:#[ここをクリックしてPythonテストに関するチートシートを入手してください]。このチュートリアルで説明するテクニックをまとめています。