スレッドアプリケーションのテスト
この章では、スレッドアプリケーションのテストについて学習します。また、テストの重要性についても学びます。
なぜテストするのですか?
テストの重要性について議論する前に、テストとは何かを知る必要があります。一般的に、テストとは、何かがどれだけうまく機能しているかを調べる手法です。一方、特にコンピュータプログラムやソフトウェアについて話す場合、テストはソフトウェアプログラムの機能にアクセスする手法です。
このセクションでは、ソフトウェアテストの重要性について説明します。ソフトウェア開発では、クライアントにソフトウェアをリリースする前に、再確認する必要があります。そのため、経験豊富なテストチームがソフトウェアをテストすることが非常に重要です。ソフトウェアテストの重要性を理解するには、次の点を考慮してください。
ソフトウェア品質の向上
確かに、低品質のソフトウェアを提供したい企業はなく、低品質のソフトウェアを購入したいクライアントもいません。テストは、その中のバグを見つけて修正することにより、ソフトウェアの品質を向上させます。
顧客満足度
ビジネスの最も重要な部分は、顧客の満足度です。バグのない高品質のソフトウェアを提供することで、企業は顧客満足を実現できます。
新機能の影響を軽減する
10000行のソフトウェアシステムを作成し、新しい機能を追加する必要があるとすると、開発チームはこの新しい機能がソフトウェア全体に与える影響について懸念を抱くでしょう。ここでも、テストは重要な役割を果たします。テストチームが一連の優れたテストを行った場合、壊滅的な中断の可能性から私たちを救うことができるからです。
ユーザー体験
ビジネスのもう1つの最も重要な部分は、その製品のユーザーのエクスペリエンスです。エンドユーザーが製品をシンプルで使いやすいと感じることを保証できるのは、テストだけです。
経費の削減
テストでは、配信後に修正するのではなく、開発のテスト段階でバグを見つけて修正することにより、ソフトウェアの総コストを削減できます。ソフトウェアの納品後に大きなバグが発生した場合、費用などの有形コストと、顧客の不満や企業の評判などの無形コストが増加します。
何をテストしますか?
何をテストするかについて適切な知識を持っていることを常にお勧めします。このセクションでは、ソフトウェアをテストする際のテスターの主な動機を最初に理解します。コードカバレッジ、つまり、テスト中にテストスイートがヒットするコードの行数は避ける必要があります。これは、テスト中、コードの行数だけに焦点を当てても、システムに実際の価値がないためです。いくつかのバグが残っている可能性があります。これらのバグは、展開後も後の段階で反映されます。
何をテストするかに関連する次の重要なポイントを考慮してください-
コードカバレッジではなく、コードの機能のテストに焦点を当てる必要があります。
最初にコードの最も重要な部分をテストしてから、コードの重要性の低い部分に移動する必要があります。それは間違いなく時間を節約します。
テスターは、ソフトウェアを限界まで押し上げることができるさまざまなテストを行う必要があります。
並行ソフトウェアプログラムをテストするためのアプローチ
マルチコアアーキテクチャの真の機能を利用できるため、並行ソフトウェアシステムが順次システムに取って代わりつつあります。最近では、携帯電話から洗濯機、車から飛行機など、あらゆるもので並行システムプログラムが使用されています。単一スレッドアプリケーションに複数のスレッドを追加した場合、次のような並行ソフトウェアプログラムのテストにはさらに注意が必要です。すでにバグがあると、複数のバグが発生します。
並行ソフトウェアプログラムのテスト手法は、競合状態、デッドロック、原子性の侵害などの潜在的に有害なパターンを明らかにするインターリーブの選択に広く焦点を合わせています。以下は、並行ソフトウェアプログラムをテストするための2つのアプローチです-
体系的な調査
このアプローチは、インターリーブの空間を可能な限り広く探索することを目的としています。そのようなアプローチは強引な手法を採用することができ、他のアプローチは部分次数削減手法またはヒューリスティック手法を採用してインターリーブの空間を探索します。
プロパティ主導
プロパティ駆動型のアプローチは、疑わしいメモリアクセスパターンなどの特定のプロパティを公開するインターリーブの下で同時実行障害が発生する可能性が高いという観察に依存しています。さまざまなプロパティ駆動型アプローチは、競合状態、デッドロック、原子性の違反などのさまざまな障害を対象としています。これは、1つまたは他の特定のプロパティにさらに依存します。
テスト戦略
テスト戦略は、テストアプローチとも呼ばれます。この戦略は、テストの実行方法を定義します。テストアプローチには2つの手法があります-
プロアクティブ
ビルドが作成される前に欠陥を見つけて修正するために、テスト設計プロセスをできるだけ早く開始するアプローチ。
反応性
開発プロセスが完了するまでテストを開始しないアプローチ。
Pythonプログラムにテスト戦略やアプローチを適用する前に、ソフトウェアプログラムで発生する可能性のあるエラーの種類について基本的な考え方を理解しておく必要があります。エラーは次のとおりです-
構文エラー
プログラム開発中に、多くの小さなエラーが発生する可能性があります。エラーは主に入力ミスが原因です。たとえば、コロンがない、キーワードのスペルが間違っているなどです。このようなエラーは、プログラムの構文の誤りが原因であり、ロジックの誤りが原因ではありません。したがって、これらのエラーは構文エラーと呼ばれます。
セマンティックエラー
セマンティックエラーは、論理エラーとも呼ばれます。ソフトウェアプログラムに論理的または意味的なエラーがある場合、ステートメントは正しくコンパイルおよび実行されますが、論理が正しくないため、目的の出力が得られません。
ユニットテスト
これは、Pythonプログラムをテストするために最もよく使用されるテスト戦略の1つです。この戦略は、コードのユニットまたはコンポーネントをテストするために使用されます。ユニットまたはコンポーネントとは、コードのクラスまたは関数を意味します。ユニットテストは、「小さな」ユニットをテストすることにより、大規模なプログラミングシステムのテストを簡素化します。上記の概念の助けを借りて、ユニットテストは、ソースコードの個々のユニットをテストして、目的の出力が返されるかどうかを判断する方法として定義できます。
以降のセクションでは、単体テスト用のさまざまなPythonモジュールについて学習します。
unittestモジュール
ユニットテストの最初のモジュールは、unittestモジュールです。これはJUnitに触発され、デフォルトでPython3.6に含まれています。テストの自動化、テストのセットアップコードとシャットダウンコードの共有、テストのコレクションへの集約、およびレポートフレームワークからのテストの独立性をサポートします。
以下は、unittestモジュールでサポートされているいくつかの重要な概念です。
テキストフィクスチャ
これは、テストを開始する前に実行し、テストの終了後に破棄できるようにテストを設定するために使用されます。テストを開始する前に必要な一時データベース、ディレクトリなどの作成が含まれる場合があります。
テストケース
テストケースは、必要な応答が特定の入力セットからのものであるかどうかを確認します。unittestモジュールには、新しいテストケースを作成するために使用できるTestCaseという名前の基本クラスが含まれています。デフォルトで2つのメソッドが含まれています-
setUp()−テストフィクスチャを実行する前にセットアップするためのフックメソッド。これは、実装されたテストメソッドを呼び出す前に呼び出されます。
tearDown( −クラス内のすべてのテストを実行した後、クラスフィクスチャを分解するためのフックメソッド。
テストスイート
これは、テストスイート、テストケース、またはその両方のコレクションです。
テストランナー
テストケースまたはスーツの実行を制御し、ユーザーに結果を提供します。結果を提供するためにGUIまたは単純なテキストインターフェイスを使用する場合があります。
Example
次のPythonプログラムは、unittestモジュールを使用して、という名前のモジュールをテストします。 Fibonacci。このプログラムは、数値のフィボナッチ数列を計算するのに役立ちます。この例では、さまざまなメソッドを使用してテストケースを定義するために、Fibo_testという名前のクラスを作成しました。これらのメソッドは、unittest.TestCaseから継承されます。デフォルトでは、setUp()とtearDown()の2つのメソッドを使用しています。また、testfibocalメソッドを定義します。テストの名前は、文字テストで開始する必要があります。最後のブロックで、unittest.main()はテストスクリプトへのコマンドラインインターフェイスを提供します。
import unittest
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
class Fibo_Test(unittest.TestCase):
def setUp(self):
print("This is run before our tests would be executed")
def tearDown(self):
print("This is run after the completion of execution of our tests")
def testfibocal(self):
self.assertEqual(fib(0), 0)
self.assertEqual(fib(1), 1)
self.assertEqual(fib(5), 5)
self.assertEqual(fib(10), 55)
self.assertEqual(fib(20), 6765)
if __name__ == "__main__":
unittest.main()
コマンドラインから実行すると、上記のスクリプトは次のような出力を生成します-
出力
This runs before our tests would be executed.
This runs after the completion of execution of our tests.
.
----------------------------------------------------------------------
Ran 1 test in 0.006s
OK
わかりやすくするために、フィボナッチモジュールの定義に役立つコードを変更します。
例として次のコードブロックを考えてみましょう-
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
以下に示すように、コードブロックにいくつかの変更が加えられています。
def fibonacci(n):
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
変更したコードでスクリプトを実行すると、次の出力が得られます。
This runs before our tests would be executed.
This runs after the completion of execution of our tests.
F
======================================================================
FAIL: testCalculation (__main__.Fibo_Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unitg.py", line 15, in testCalculation
self.assertEqual(fib(0), 0)
AssertionError: 1 != 0
----------------------------------------------------------------------
Ran 1 test in 0.007s
FAILED (failures = 1)
上記の出力は、モジュールが目的の出力を提供できなかったことを示しています。
ドックテストモジュール
docktestモジュールは、ユニットテストにも役立ちます。また、Pythonがあらかじめパッケージ化されています。unittestモジュールよりも使いやすいです。unittestモジュールは、複雑なテストに適しています。doctestモジュールを使用するには、それをインポートする必要があります。対応する関数のdocstringには、出力とともにインタラクティブなpythonセッションが必要です。
コードですべてが正常であれば、docktestモジュールからの出力はありません。それ以外の場合は、出力を提供します。
例
次のPythonの例では、docktestモジュールを使用して、フィボナッチという名前のモジュールをテストします。これは、数値のフィボナッチ数列の計算に役立ちます。
import doctest
def fibonacci(n):
"""
Calculates the Fibonacci number
>>> fibonacci(0)
0
>>> fibonacci(1)
1
>>> fibonacci(10)
55
>>> fibonacci(20)
6765
>>>
"""
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
if __name__ == "__main__":
doctest.testmod()
fibという名前の対応する関数のdocstringには、出力とともにインタラクティブなpythonセッションがあったことがわかります。コードに問題がなければ、doctestモジュールからの出力はありません。しかし、それがどのように機能するかを確認するには、–vオプションを使用して実行できます。
(base) D:\ProgramData>python dock_test.py -v
Trying:
fibonacci(0)
Expecting:
0
ok
Trying:
fibonacci(1)
Expecting:
1
ok
Trying:
fibonacci(10)
Expecting:
55
ok
Trying:
fibonacci(20)
Expecting:
6765
ok
1 items had no tests:
__main__
1 items passed all tests:
4 tests in __main__.fibonacci
4 tests in 2 items.
4 passed and 0 failed.
Test passed.
ここで、フィボナッチモジュールの定義に役立つコードを変更します
例として次のコードブロックを考えてみましょう-
def fibonacci(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
次のコードブロックは変更に役立ちます-
def fibonacci(n):
a, b = 1, 1
for i in range(n):
a, b = b, a + b
return a
–vオプションを指定せずにスクリプトを実行した後、コードを変更すると、次のような出力が得られます。
出力
(base) D:\ProgramData>python dock_test.py
**********************************************************************
File "unitg.py", line 6, in __main__.fibonacci
Failed example:
fibonacci(0)
Expected:
0
Got:
1
**********************************************************************
File "unitg.py", line 10, in __main__.fibonacci
Failed example:
fibonacci(10)
Expected:
55
Got:
89
**********************************************************************
File "unitg.py", line 12, in __main__.fibonacci
Failed example:
fibonacci(20)
Expected:
6765
Got:
10946
**********************************************************************
1 items had failures:
3 of 4 in __main__.fibonacci
***Test Failed*** 3 failures.
上記の出力から、3つのテストが失敗したことがわかります。