テストを含むpytestクラスの設定と破棄を正しく行うにはどうすればよいですか?


100

エンドツーエンドのテストにセレンを使用していますが、使用方法setup_classteardown_class方法を取得できません。

setup_classメソッドでブラウザを設定してから、クラスメソッドとして定義された一連のテストを実行し、最後にteardown_classメソッドでブラウザを終了する必要があります。

しかし、実際には私のテストはクラスではなくオブジェクトで機能するため、論理的には悪い解決策のように見えます。selfすべてのテストメソッド内でparam を渡すので、オブジェクトの変数にアクセスできます。

class TestClass:
  
    def setup_class(cls):
        pass
        
    def test_buttons(self, data):
        # self.$attribute can be used, but not cls.$attribute?  
        pass
        
    def test_buttons2(self, data):
        # self.$attribute can be used, but not cls.$attribute?
        pass
        
    def teardown_class(cls):
        pass
    

そして、クラスのブラウザインスタンスを作成するのは正しくないようです。すべてのオブジェクトに対して個別に作成する必要がありますよね。

では、__init__andの__del__代わりにsetup_classand メソッドを使用する必要がありteardown_classますか?

回答:


93

Fixtureのファイナライズ/ティアダウンコードの実行によると、セットアップとティアダウンの現在のベストプラクティスは、次のyield代わりに使用することですreturn

import pytest

@pytest.fixture()
def resource():
    print("setup")
    yield "resource"
    print("teardown")

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

それを実行すると

$ py.test --capture=no pytest_yield.py
=== test session starts ===
platform darwin -- Python 2.7.10, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
collected 1 items

pytest_yield.py setup
testing resource
.teardown


=== 1 passed in 0.01 seconds ===

ティアダウンコードを記述する別の方法は、フィクスチャ関数にrequest-contextオブジェクトを受け入れrequest.addfinalizer、ティアダウンを1回または複数回実行する関数でそのメソッドを呼び出すことです。

import pytest

@pytest.fixture()
def resource(request):
    print("setup")

    def teardown():
        print("teardown")
    request.addfinalizer(teardown)
    
    return "resource"

class TestResource:
    def test_that_depends_on_resource(self, resource):
        print("testing {}".format(resource))

これを、リソースが必要になるすべてのテストファイルにコピーしますか?
アンディヘイデン

あなたの備品を書く方法に応じて@AndyHayden、あなたがそれを必要とするか、またはあなたがconftest.pyファイルにそれを置くことができ、すべてのテストファイルにそれを置くことができstackoverflow.com/questions/34466027/...
エベレットToews

2
しかし、これはクラスのセットアップではありませんよね?クラス内のすべてのテストメソッドの前に実行されます。
マルハー

1
この特定のケースでは、テストメソッドでパラメーターとして使用された場合にのみ実行されます。例えばresource内のparamtest_that_depends_on_resource(self, resource)
エヴェレットToews

64

「クラスメソッドとして定義されたテスト」を書くとき、クラスメソッドクラスを最初のパラメーターとして受け取るメソッド)または通常のメソッド(インスタンスを最初のパラメーターとして受け取るメソッド)を本当に意味しますか?

あなたの例selfではテストメソッドを使用しているので、後者を想定しているので、setup_method代わりに使用する必要があります:

class Test:

    def setup_method(self, test_method):
        # configure self.attribute

    def teardown_method(self, test_method):
        # tear down self.attribute

    def test_buttons(self):
        # use self.attribute for test

テストメソッドのインスタンスはsetup_methodand teardown_methodに渡されますが、セットアップ/ティアダウンコードがテストコンテキストを知る必要がない場合は無視できます。詳細については、こちらをご覧ください

また、py.testのフィクスチャはより強力な概念であるため、これらに慣れることをお勧めします。


1
フィクスチャはクラスメソッドよりも弱く、フィクスチャによって作成されていないオブジェクトを破壊することはできません(多くの場合、これは本当に必要なことです)。それ以外は、情報ありがとうございます。
wvxvw

これは、コードベースをpytestの3.0.xリリースから4.xバリアントにアップグレードするときに私を襲いました。setup_classモック化されたメソッドなどで使用されるいくつかの古いコードは、近代化する必要がありました。setup_class(self, foo, bar)->setup_method(self,function,foo,bar)
jxramos

28

これはhttp://docs.pytest.org/en/latest/xunit_setup.htmlを助けるかもしれません

テストスイートでは、テストケースをクラスにグループ化します。そのクラスのすべてのテストケースに必要なセットアップとティアダウンには、setup_class(cls)およびteardown_class(cls)クラスメソッドを使用します。

また、各テストケースに必要なセットアップとティアダウンには、setup_method(method)およびteardown_method(methods)

例:

lh = <got log handler from logger module>

class TestClass:
    @classmethod
    def setup_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    @classmethod
    def teardown_class(cls):
        lh.info("starting class: {} execution".format(cls.__name__))

    def setup_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def teardown_method(self, method):
        lh.info("starting execution of tc: {}".format(method.__name__))

    def test_tc1(self):
        <tc_content>
        assert 

    def test_tc2(self):
        <tc_content>
        assert

テストを実行すると、TestClassの実行が開始されると、実行の開始時、実行の終了時、およびメソッドについて同じ詳細がログに記録されます。

それぞれの場所にある可能性のある他のセットアップおよび破棄の手順を追加できます。

それが役に立てば幸い!


こんにちは@ Kiran、setup_classvs の違いは何setup_methodですか?
imsrgadich

1
@imsrgadichテストケースをクラスに編成する場合、<setup / teardown> _classはクラスのセットアップおよびティアダウンステップに使用され、<setup / teardown> _methodは各テストケースメソッドのそれぞれのステップです。
キランヴェムリ

1
くそー...今私はそれを手に入れました!数時間それで立ち往生していました。だから、物事を展望するために。<setup/teardown>_classクラス全体のために。ここでは、DBへのリンクの設定やデータファイルのロードなどが可能です。そして、各テストケースはの形式で独自の設定を持つことができます<setup/teardown>_method。物事は今非常に明確です。どうもありがとう!
imsrgadich

24

@Brunoが提案したように、pytestフィクスチャを使用することは、両方のテストクラスまたは単純なテスト関数でもアクセスできる別のソリューションです。python2.7関数をテストする例を次に示します

import pytest

@pytest.fixture(scope='function')
def some_resource(request):
    stuff_i_setup = ["I setup"]

    def some_teardown():
        stuff_i_setup[0] += " ... but now I'm torn down..."
        print stuff_i_setup[0]
    request.addfinalizer(some_teardown)

    return stuff_i_setup[0]

def test_1_that_needs_resource(some_resource):
    print some_resource + "... and now I'm testing things..."

したがって、実行test_1...すると以下が生成されます:

I setup... and now I'm testing things...
I setup ... but now I'm torn down...

通知stuff_i_setup固定具で参照され、オブジェクトがすることを可能にsetupし、torn downそれとの相互作用のテストのために。これは、架空のデータベースや一部の接続など、各テストを実行する前に消去してそれらを分離しておく必要がある永続オブジェクトに役立つと想像できます。


13

コードは、@classmethodデコレータを追加した場合と同じように機能するはずです。

@classmethod 
def setup_class(cls):
    "Runs once per class"

@classmethod 
def teardown_class(cls):
    "Runs at end of class"

http://pythontesting.net/framework/pytest/pytest-xunit-style-fixtures/を参照してください


これは、ドキュメントに記載されている内容とほぼ同じです。ドキュメントで発生した問題は、コンテキストを理解するのが難しかったことです。セルフは伝統的にclsではなくselfと呼ばれているため、クラス自体のコンテキストから外れているように見えました。上記のKiranがこのコンテキストを提供します。
Cognitiaclaeves

1
@Cognitiaclaeves 「自己が伝統的ではなく、CLS自己と呼ばれ、」はい、selfつつ、最初の引数は、メソッド操作が行われた上で特定のオブジェクトインスタンスであるインスタンスメソッドのために使用されるclsために使用される@classmethodにバインドされ、S、クラスであり、クラスのインスタンス(オブジェクト)ではありません。
code_dredd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.