Table Of Contents

Previous topic

基本的なパターンと例

Next topic

パラメーターテスト

Mysetup パターン: アプリケーションに特化したテストフィクスチャ

アプリケーションに特化したテストのセットアップを管理したり、相互にやり取りする、基本的且つ便利なサンプルを順を追って紹介します。その目的としては、アプリケーションオブジェクトの一連の開始処理や設定のグルーコードやテストコードを1つの場所に集め、実行時にテストモジュールとテスト関数からそういった処理の詳細を見えなくすることです。

ステップ 1: アプリケーションに特化した mysetup パターンの実装

mysetup という関数の引数を使って、簡単なテスト関数を書いてみましょう:

# test_sample.py の内容
def test_answer(mysetup):
    app = mysetup.myapp()
    answer = app.question()
    assert answer == 42

このテストを実行するために py.test は、関数の引数に与えられた mysetup を扱うファクトリー関数を探して呼び出す必要があります。このファクトリー関数を探し出せるように local プラグイン に特別な名前をもつファクトリーメソッドを書きます:

# conftest.py の内容
from myapp import MyApp

def pytest_funcarg__mysetup(request): # "mysetup" ファクトリー関数
    return MySetup()

class MySetup: # このインスタンスはテスト関数から見える
    def myapp(self):
        return MyApp()

このサンプルを実行するために MyApp アプリケーションオブジェクトの簡単なスタブを作ります:

# myapp.py の内容
class MyApp:
    def question(self):
        return 6 * 9

テストを実行します:

$ py.test test_sample.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.1 -- pytest-2.2.4
collecting ... collected 1 items

test_sample.py F

================================= FAILURES =================================
_______________________________ test_answer ________________________________

mysetup = <conftest.MySetup instance at 0x17f21b8>

    def test_answer(mysetup):
        app = mysetup.myapp()
        answer = app.question()
>       assert answer == 42
E       assert 54 == 42

test_sample.py:4: AssertionError
========================= 1 failed in 0.01 seconds =========================

mysetup オブジェクトが正常にインスタンス化されて、 mysetup.app() が初期化された MyApp インスタンスを返しました。あなたが具体的に何を聞けば良いのか、もしくは実際に何が起こったかに混乱しているなら、その質問に関して尋ねられます。 ここ をご覧ください。

ステップ 2: コマンドラインオプションとテストのスキップを確認

コマンドラインオプションを追加するには、前述したサンプルの conftest.py に、コマンドラインオプションを追加して新たな mysetup メソッドを提供するように変更します:

# ./conftest.py の内容
import pytest
from myapp import MyApp

def pytest_funcarg__mysetup(request): # "mysetup" ファクトリー関数
    return MySetup(request)

def pytest_addoption(parser):
    parser.addoption("--ssh", action="store", default=None,
        help="specify ssh host to run tests with")


class MySetup:
    def __init__(self, request):
        self.config = request.config

    def myapp(self):
        return MyApp()

    def getsshconnection(self):
        host = self.config.option.ssh
        if host is None:
            pytest.skip("specify ssh host with --ssh")
        return execnet.SshGateway(host)

次のようにテスト関数から mysetup.getsshconnection() メソッドを使えます:

# test_ssh.py の内容
class TestClass:
    def test_function(self, mysetup):
        conn = mysetup.getsshconnection()
        # conn を使ってテストする

実行すると次のようなレポートが表示されます:

$ py.test test_ssh.py -rs
=========================== test session starts ============================
platform linux2 -- Python 2.7.1 -- pytest-2.2.4
collecting ... collected 1 items

test_ssh.py s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-220/conftest.py:22: specify ssh host with --ssh

======================== 1 skipped in 0.01 seconds =========================

py.test --ssh=python.org のようにコマンドラインオプションを指定すると、期待した通りにテストが実行されます。

TestClasstest_function のどちらとも、テストの状態をセットアップする方法について何も知る必要がないことに注目してください。 conftest.py ファイルの “テストをセットアップするグルー” コードは別々に処理されます。テストコード内で必要に応じて mysetup オブジェクトを拡張するのは簡単です。 conftest.py ファイルの配下にあるファイルやディレクトリの、任意のテスト関数によって使われます。