Python テストの基本

PythonPythonBeginner
今すぐ練習

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

Python の動的な性質により、テストはほとんどのアプリケーションにとって極めて重要です。バグを見つけるためのコンパイラはありません。バグを見つける唯一の方法は、コードを実行して、そのすべての機能を試してみることです。

アサーション

assert 文は、プログラムの内部チェックに使用されます。式が真でない場合、AssertionError 例外を発生させます。

assert 文の構文。

assert <式> [, '診断メッセージ']

例。

assert isinstance(10, int), 'Expected int'

ユーザー入力(つまり、Web フォームなどで入力されたデータ)をチェックするためには使用しないでください。その目的は、主に内部チェックと不変条件(常に真であるはずの条件)のためです。

契約型プログラミング

契約による設計とも呼ばれ、アサーションを十分に利用することはソフトウェアを設計するためのアプローチです。ソフトウェアのコンポーネントに対して正確なインターフェイス仕様を定義するようソフトウェア設計者に求めます。

たとえば、関数のすべての入力にアサーションを置くことができます。

def add(x, y):
    assert isinstance(x, int), 'Expected int'
    assert isinstance(y, int), 'Expected int'
    return x + y

入力をチェックすることで、適切な引数を使用していない呼び出し元を直ちにキャッチすることができます。

>>> add(2, 3)
5
>>> add('2', '3')
Traceback (most recent call last):
...
AssertionError: Expected int
>>>

インラインテスト

アサーションは、単純なテストにも使用できます。

def add(x, y):
    return x + y

assert add(2,2) == 4

このようにして、コードと同じモジュールにテストを含めることができます。

利点:コードが明らかに破損している場合、モジュールをインポートしようとするとクラッシュします。

これは網羅的なテストには推奨されません。基本的な「スモークテスト」に近いものです。関数が何らかの例で機能するかどうかです。もし機能しない場合、何かが間違っていることは確かです。

unittest モジュール

simple.py にいくつかのコードがあるとしましょう。

## simple.py

def add(x, y):
    return x + y

次に、それをテストしたいとします。/home/labex/project/test_simple.py にこのような別のテストファイルを作成します。

## test_simple.py

import simple
import unittest

そして、テストクラスを定義します。

## test_simple.py

import simple
import unittest

## 注意:unittest.TestCase から継承しています
class TestAdd(unittest.TestCase):
  ...

テストクラスは unittest.TestCase から継承する必要があります。

テストクラスの中で、テストメソッドを定義します。

## test_simple.py

import simple
import unittest

## 注意:unittest.TestCase から継承しています
class TestAdd(unittest.TestCase):
    def test_simple(self):
        ## 単純な整数引数でテスト
        r = simple.add(2, 2)
        self.assertEqual(r, 5)
    def test_str(self):
        ## 文字列を使ったテスト
        r = simple.add('hello', 'world')
        self.assertEqual(r, 'helloworld')

*重要:各メソッドは test で始める必要があります。

unittest の使用方法

unittest にはいくつかの組み込みアサーションがあります。それぞれが異なることをアサートします。

## expr が真であることをアサートする
self.assertTrue(expr)

## x == y であることをアサートする
self.assertEqual(x,y)

## x!= y であることをアサートする
self.assertNotEqual(x,y)

## x が y に近いことをアサートする
self.assertAlmostEqual(x,y,places)

## callable(arg1,arg2,...) が exc を発生させることをアサートする
self.assertRaises(exc, callable, arg1, arg2,...)

これは網羅的な一覧ではありません。モジュールには他にもアサーションがあります。

unittest の実行

テストを実行するには、コードをスクリプトに変換します。

## test_simple.py

...

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

そして、テストファイルで Python を実行します。

$ python3 test_simple.py
F.
========================================================
FAIL: test_simple (__main__.TestAdd)
--------------------------------------------------------
Traceback (most recent call last):
  File "testsimple.py", line 8, in test_simple
    self.assertEqual(r, 5)
AssertionError: 4!= 5
--------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)

解説

効果的な単体テストは技術であり、大規模なアプリケーションではかなり複雑になることがあります。

unittest モジュールには、テストランナー、結果の収集、およびテストのその他の側面に関連する多数のオプションがあります。詳細については、ドキュメントを参照してください。

サードパーティのテストツール

組み込みの unittest モジュールはどこでも利用できるという利点があります。Python の一部ですからです。しかし、多くのプログラマーはこれが非常に冗長であると感じています。人気のある代替策は pytest です。pytest を使うと、テストファイルは次のように簡略化されます。

## test_simple.py
import simple

def test_simple():
    assert simple.add(2,2) == 4

def test_str():
    assert simple.add('hello','world') == 'helloworld'

テストを実行するには、python -m pytest のようなコマンドを入力するだけです。すると、すべてのテストを見つけて実行します。このモジュールは pip install pytest を使ってインストールできます。

この例だけでは pytest についてはまだたくさんありますが、試してみることにした場合は、通常簡単に始めることができます。

この演習では、Python の unittest モジュールを使う基本的な仕組みを調べます。

以前の演習では、Stock クラスを含む stock.py ファイルを書きました。この演習では、7.9 の演習で書かれた型付きプロパティを含むコードを使っていると仮定しています。何らかの理由でそれが機能しない場合は、Solutions/7_9 のソリューションを作業ディレクトリにコピーすることができます。

演習8.1:単体テストの作成

別のファイル test_stock.py で、Stock クラスの単体テストのセットを書きます。始めに、インスタンス作成をテストする小さなコード断片を以下に示します。

## test_stock.py

import unittest
import stock

class TestStock(unittest.TestCase):
    def test_create(self):
        s = stock.Stock('GOOG', 100, 490.1)
        self.assertEqual(s.name, 'GOOG')
        self.assertEqual(s.shares, 100)
        self.assertEqual(s.price, 490.1)

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

単体テストを実行します。以下のような出力が得られるはずです。

.

Ran 1 tests in 0.000s

OK

機能することが確認できたら、以下をチェックする追加の単体テストを書きます。

  • s.cost プロパティが正しい値(49010.0)を返すことを確認する。
  • s.sell() メソッドが正しく機能することを確認する。s.shares の値がそれに応じて減少する必要がある。
  • s.shares 属性が整数以外の値に設定できないことを確認する。

最後の部分では、例外が発生することを確認する必要があります。それを行う簡単な方法は、以下のようなコードを使うことです。

class TestStock(unittest.TestCase):
  ...
    def test_bad_shares(self):
         s = stock.Stock('GOOG', 100, 490.1)
         with self.assertRaises(TypeError):
             s.shares = '100'
✨ 解答を確認して練習

まとめ

おめでとうございます! あなたはテストの実験を完了しました。あなたの技術を向上させるために、LabExでさらに多くの実験を練習することができます。