PythonのUTフレームワークを選ぶ

目次

目次:

はじめに

PythonのUTフレームワークを選びたい。 JavaのようにJUnitかTestNGか、どちらも大差がないような状況であれば選ぶは簡単だ。 しかしPythonのフレームワークを探してみると数だけでも沢山あるので整理したい。

Python:2023年でも使えるフレームワーク

この中から選びたい。フレームワーク6選。 執筆時点:2022/07/02

  1. pytest
  2. robotframework
  3. nose2
  4. testify
  5. unittest
  6. doctest

Pythonテストは3パターンから選べる

個人的な結論としては「pytest + robotframework」になる。 UTだけでいえばpytestを選択する。

Pythonのテストフレームワークについて調べた結果、現在あるフレームワークは「UT用」と「受け入れテスト用」がある。 「UT用」の中では「オブジェクト指向的なテスト方法」と「関数的なテスト方法」に分けられる。

robotframeworkは受け入れテストなどに使用するものなのでUTの後から使用するものとして分類できる。

パターン1:pytest + robotframework

  1. pytestは関数単位でテストできる。
  2. エラーの箇所が特定しやすく見やすい。
  3. 検索で出てくる情報量が多い。
  4. メンテナンス体制が盤石なため将来もつかいつづけられそうな期待ができる。

パターン2:unittest + nose2 + robotframework

  1. オブジェクト指向的なテスト方法ができる。
  2. JUnitに慣れているとやりやすい。
  3. buit-inなのでメンテナンスは問題ない。
  4. nose2でunittestを拡張できる。

パターン3:testify + robotframework

  1. 新しい。
  2. unittest + nose2を置き換えるようなもの。

doctest

始めやすい。わかりやすい。本格的なUTとしてではなく簡易的なものとして使えそう。

Pythonテストフレームワーク簡易まとめ

 

pytest

version lisence phase install
7.1.2 MIT UT pip install pytest
  • pytestは汎用的にテストのフレームワークとして使用することができる。
  • API、データベース、およびUIをテストするための単純または複雑なテキストコードをサポートする。
  • テストケースの構文は単純。
  • 「test_」から始まるファイルがテスト対処として処理される。
  • 豊富なプラグインと並行してテストを実行することが可能。
  • 関数単位のテストが実行可能。
  • エラー箇所のコードを表示が見やすい。

pytestフレームワークは、小さなテストを簡単に書くことができ、かつアプリケーションやライブラリの複雑な機能テストをサポートするように拡張することができます。

pytestをはじめとする数多くのパッケージのメンテナは、Tideliftと協力して、アプリケーションの構築に使用するオープンソースの依存関係の商用サポートとメンテナンスを提供しています。 時間を節約し、リスクを減らし、コードの健全性を向上させながら、あなたが使用している依存関係のメンテナにお金を払うことができます。

example code

# content of test_sample.py
def inc(x):
    return x + 1


def test_answer():
    assert inc(3) == 5

robotframework

version lisence phase install
5.0.1 MIT AT pip install robotframework

Robot Framework は、Python ベースの拡張可能なキーワード駆動型 (keyword-driven) テスト自動化フレームワークです。 エンドツーエンドの受け入れテストや受け入れテスト駆動開発 (ATDD) に使えます。 Robot Framework は、分散・機種混合環境で、様々な技術・インタフェースを使わねばならないアプリケーションのテストに利用できます。

Robot Framework ® は、受け入れテスト、受け入れテスト駆動開発(ATDD)、ロボットプロセス自動化(RPA)のための汎用オープンソース自動化フレームワークです。 シンプルなプレーンテキスト構文を持ち、汎用ライブラリやカスタムライブラリで簡単に拡張することができます。

Robot Frameworkは、オペレーティングシステムやアプリケーションに依存しません。 Pythonで実装されており、Pythonは拡張のための主要な言語でもあります。 また、このフレームワークの周りには、様々な汎用ライブラリやツールからなる豊富なエコシステムがあり、これらは個別のプロジェクトとして開発されています。 Robot Frameworkとエコシステムの詳細については、http://robotframework.org を参照してください。

Robot FrameworkプロジェクトはGitHubでホストされており、ソースコード、イシュー・トラッカー、およびいくつかの詳細なドキュメントを見ることができます。 ダウンロードはPyPIで行われています。

Robot Frameworkの開発は、Robot Framework Foundationによって支援されています。 もし、あなたがこのフレームワークを使っていて、その恩恵を受けているのであれば、この財団に参加して、フレームワークの維持と発展に貢献することを検討してください。

www.DeepL.com/Translator(無料版)で翻訳しました。

example code

 *** Settings ***
Documentation     A test suite with a single test for valid login.
...
...               This test has a workflow that is created using keywords in
...               the imported resource file.
Resource          login.resource

 *** Test Cases ***
Valid Login
    Open Browser To Login Page
    Input Username    demo
    Input Password    mode
    Submit Credentials
    Welcome Page Should Be Open
    [Teardown]    Close Browser

nose2

version lisence phase install
0.11.0 BSD UT pip install nose2

nose2はnoseの後継です。 unittestにプラグインを加えたものです。 nose2は新しいプロジェクトであり、noseのすべての機能をサポートしているわけではありません。 徹底的な説明については相違点をご覧ください。 nose2の目的はunittestを拡張して、テストをよりきれいに、よりわかりやすくすることです。

nose2 と pytest の比較

nose2 はあなたのプロジェクトに合うかもしれませんし、合わないかもしれません。 Pythonのテストに慣れていないのであれば、人気のあるテストフレームワークであるpytestも検討することをお勧めします。

example code

# in test_simple.py
import unittest

class TestStrings(unittest.TestCase):
    def test_upper(self):
        self.assertEqual("spam".upper(), "SPAM")

testify

version lisence phase install
0.11.0 ASF UT pip install testify

Testify は Python の unittest モジュールと nose を置き換えるものです。unittest をモデルとしており、unittest 用に書かれたテストは testify で最小限の調整で動作しますが、unittest 以上の機能を備えています。

  • クラスレベルのセットアップとティアダウンのフィクスチャメソッド (テストメソッドのセット全体に対してそれぞれ一度ずつ実行されます)
  • フィクスチャメソッドに対するデコレータベースのアプローチにより、super()呼び出しの必要性を排除しています。
  • よりPythonicに、よりJavaに
  • テスト発見の強化 – testify はパッケージを掘り下げてテストケースを見つけることができます (nose に似ています)。
  • モジュール、クラス、メソッドをテストスイートに集めて、テストを実行することをサポートします。
  • きれいなテストランナー出力 (カラー!)
  • 拡張可能なプラグインシステムで、レポート周りの機能を追加できる。
  • 他の便利なテストユーティリティが付属しています。モッキング(タートル)、コードカバレッジの統合とプロファイリング。

unittest

version lisence pahse install
built-in GPL UT built-in

docs.python.org – unittest

unittest ユニットテストフレームワークは元々 JUnit に触発されたもので、 他の言語の主要なユニットテストフレームワークと同じような感じです。 テストの自動化、テスト用のセットアップやシャットダウンのコードの共有、テストのコレクション化、そして報告フレームワークからのテストの独立性をサポートしています。

これを実現するために、 unittest はいくつかの重要な概念をオブジェクト指向の方法でサポートしています:

テストフィクスチャ (test fixture) テストフィクスチャ (test fixture) とは、テスト実行のために必要な準備や終了処理を指します。例: テスト用データベースの作成・ディレクトリ・サーバプロセスの起動など。

テストケース (test case) テストケース (test case) はテストの独立した単位で、各入力に対する結果をチェックします。 テストケースを作成する場合は、 unittest が提供する TestCase クラスを基底クラスとして利用することができます。

テストスイート (test suite) テストスイート (test suite) はテストケースとテストスイートの集まりで、同時に実行しなければならないテストをまとめる場合に使用します。

テストランナー (test runner) テストランナー (test runner) はテストの実行を管理し結果を提供する要素です。 ランナーはグラフィカルインターフェースやテキストインターフェースを使用しても構いませんし、テストの実行結果を示す特別な値を返しても構いません。

example code

import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

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

doctest

version license phase install
built-in GPL UT built-in

docs.oython.org – doctest

doctest モジュールは、対話的 Python セッションのように見えるテキストを探し出し、セッションの内容を実行して、そこに書かれている通りに振舞うかを調べます。

doctest は以下のような用途によく使われています:

  • モジュールの docstring (ドキュメンテーション文字列) 中にある対話実行例のすべてが書かれている通りに動作するか検証することで、docstring の内容が最新かどうかチェックする。
  • テストファイルやテストオブジェクト中の対話実行例が期待通りに動作するかを検証することで、回帰テストを実現します。
  • 入出力例を豊富に使ったパッケージのチュートリアルドキュメントが書けます。入出力例と解説文のどちらに注目するかによって、ドキュメントは「読めるテスト」にも「実行できるドキュメント」にもなります。

example code

  """
This is the "example" module.

The example module supplies one function, factorial().  For example,

>>> factorial(5)
120
"""

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次