Concurrency-in-python-testing-thread-applications

提供:Dev Guides
移動先:案内検索

スレッドアプリケーションのテスト

この章では、スレッドアプリケーションのテストについて学習します。 また、テストの重要性も学びます。

テストする理由

テストの重要性について議論する前に、テストとは何かを知る必要があります。 一般的に、テストとは、何かがうまく機能しているかどうかを調べる手法です。 一方、特にコンピュータープログラムまたはソフトウェアについて話す場合、テストはソフトウェアプログラムの機能にアクセスする手法です。

このセクションでは、ソフトウェアテストの重要性について説明します。 ソフトウェア開発では、クライアントにソフトウェアをリリースする前に二重チェックが必要です。 そのため、経験豊富なテストチームがソフトウェアをテストすることが非常に重要です。 ソフトウェアテストの重要性を理解するために、次の点を考慮してください-

ソフトウェア品質の改善

確かに、低品質のソフトウェアを提供したい企業や低品質のソフトウェアを購入したいクライアントはいません。 テストは、その中のバグを見つけて修正することにより、ソフトウェアの品質を向上させます。

顧客満足度

ビジネスの最も重要な部分は、顧客の満足度です。 バグのない良質のソフトウェアを提供することにより、企業は顧客満足度を達成できます。

新機能の影響を軽減

10000行のソフトウェアシステムを作成し、新しい機能を追加する必要があると仮定すると、開発チームはこの新しい機能がソフトウェア全体に及ぼす影響について懸念を持つことになります。 ここでも、テストが重要な役割を果たします。テストチームが適切なテストスイートを作成した場合、壊滅的な中断から私たちを救うことができるからです。

ユーザー体験

ビジネスのもう1つの最も重要な部分は、その製品のユーザーのエクスペリエンスです。 エンドユーザーが製品をシンプルかつ簡単に使用できることを確認できるのは、テストのみです。

経費削減

テストでは、配布後に修正するのではなく、開発のテスト段階でバグを見つけて修正することにより、ソフトウェアの総コストを削減できます。 ソフトウェアの配信後に大きなバグがある場合、費用の観点から見た具体的なコストと、顧客の不満、会社の否定的な評判などの観点から見た無形コストが増加します。

何をテストしますか?

テスト対象について適切な知識を持つことが常に推奨されます。 このセクションでは、まずソフトウェアをテストする際のテスターの主な動機であることを理解します。 コードカバレッジ、つまり、テスト中にテストスイートがヒットするコードの行数は避ける必要があります。 これは、テスト中にコードの行数だけに焦点を合わせると、システムに実質的な価値が追加されないためです。 いくつかのバグが残っている場合があり、それらは展開後でも後の段階で反映されます。

テスト対象に関連する次の重要な点を考慮してください-

  • コードカバレッジではなく、コードの機能のテストに集中する必要があります。
  • 最初にコードの最も重要な部分をテストし、次にコードの重要度の低い部分に向かって移動する必要があります。 それは間違いなく時間を節約します。
  • テスターは、ソフトウェアを限界までプッシュできるさまざまなテストを行う必要があります。

並行ソフトウェアプログラムをテストするためのアプローチ

マルチコアアーキテクチャの真の機能を利用できるため、コンカレントソフトウェアシステムがシーケンシャルシステムに取って代わります。 最近では、携帯電話から洗濯機、車から飛行機など、すべてで並行システムプログラムが使用されています。 すでにバグが存在する単一のスレッドアプリケーションに複数のスレッドを追加した場合、複数のバグが発生するため、並行ソフトウェアプログラムのテストにはさらに注意する必要があります。

並行ソフトウェアプログラムのテスト手法は、競合状態、デッドロック、アトミック性の違反などの潜在的に有害なパターンを公開するインターリーブの選択に重点を置いています。 以下は、並行ソフトウェアプログラムをテストするための2つのアプローチです-

体系的な調査

このアプローチは、インターリーブのスペースをできるだけ広く探索することを目的としています。 そのようなアプローチはブルートフォース技術を採用でき、他のアプローチは半順序縮小技術またはヒューリスティック技術を採用してインターリーブの空間を探索できます。

プロパティ駆動

プロパティ駆動型のアプローチは、疑わしいメモリアクセスパターンなどの特定のプロパティを公開するインターリーブで並行性障害が発生する可能性が高いという観察に依存しています。 さまざまなプロパティ駆動型のアプローチは、競合状態、デッドロック、原子性の違反など、さまざまな障害を対象としています。これらは、1つまたは他の特定のプロパティにさらに依存します。

テスト戦略

テスト戦略は、テストアプローチとしても知られています。 この戦略は、テストの実行方法を定義します。 テストアプローチには2つのテクニックがあります-

積極的

ビルドを作成する前に欠陥を見つけて修正するために、テスト設計プロセスをできるだけ早く開始するアプローチ。

リアクティブ

開発プロセスが完了するまでテストを開始しないアプローチ。

pythonプログラムにテスト戦略またはアプローチを適用する前に、ソフトウェアプログラムに発生する可能性のあるエラーの種類についての基本的な考え方が必要です。 エラーは次のとおりです-

構文エラー

プログラム開発中に、多くの小さなエラーが発生する可能性があります。 エラーは主に入力ミスによるものです。 たとえば、コロンの欠落やキーワードのつづりの誤りなど。 このようなエラーは、ロジックではなくプログラム構文の誤りによるものです。 したがって、これらのエラーは構文エラーと呼ばれます。

セマンティックエラー

セマンティックエラーは、論理エラーとも呼ばれます。 ソフトウェアプログラムに論理的または意味的なエラーがある場合、ステートメントは正しくコンパイルおよび実行されますが、ロジックが正しくないため、目的の出力が得られません。

単体テスト

これは、Pythonプログラムをテストするために最も使用されるテスト戦略の1つです。 この戦略は、コードのユニットまたはコンポーネントのテストに使用されます。 ユニットまたはコンポーネントとは、コードのクラスまたは機能を意味します。 ユニットテストは、「小さな」ユニットをテストすることにより、大規模なプログラミングシステムのテストを簡素化します。 上記の概念の助けを借りて、単体テストは、ソースコードの個々のユニットがテストされて、目的の出力が返されるかどうかを判断する方法として定義できます。

以降のセクションでは、単体テスト用のさまざまなPythonモジュールについて学習します。

unittestモジュール

ユニットテストの最初のモジュールはユニットテストモジュールです。 JUnitに触発され、デフォルトでPython3.6に含まれています。 テストの自動化、テストのセットアップおよびシャットダウンコードの共有、テストのコレクションへの集約、レポートフレームワークからのテストの独立性をサポートします。

以下は、unittestモジュールでサポートされるいくつかの重要な概念です。

テキストフィクスチャ

テストを開始する前に実行し、テストの終了後に解体できるように、テストを設定するために使用されます。 一時データベース、ディレクトリなどの作成が含まれる場合があります。 テストを開始する前に必要です。

テストケース

テストケースは、必要な応答が特定の入力セットから来ているかどうかをチェックします。 unittestモジュールには、新しいテストケースの作成に使用できるTestCaseという名前の基本クラスが含まれています。 デフォルトで2つの方法が含まれています-

  • * setUp()*-テストフィクスチャを実行する前にセットアップするフックメソッド。 これは、実装されたテストメソッドを呼び出す前に呼び出されます。
  • * tearDown(*-クラス内のすべてのテストを実行した後、クラスフィクスチャを分解するためのフックメソッド。

テストスイート

これは、テストスイート、テストケース、またはその両方のコレクションです。

テストランナー

テストケースまたはスーツの実行を制御し、結果をユーザーに提供します。 結果を提供するために、GUIまたはシンプルなテキストインターフェイスを使用できます。

次の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モジュールを使用してFibonacciというモジュールをテストします。これは、数値のフィボナッチ数列の計算に役立ちます。

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つのテストが失敗したことがわかります。