2013-08-05 13 views
10

ベースクラスで@ pytest.markを使用するには?私はpy.test 2.2.4を使用していますし、次のように私のテストケースが整理されてい

import pytest 

class BaseTests(): 
    def test_base_test(self): 
     pass 

@pytest.mark.linuxonly 
class TestLinuxOnlyLocal(BaseTests): 
    pass 

@pytest.mark.windowsonly 
class TestWindowsOnly(BaseTests): 
    pass 

class TestEverywhere(BaseTests): 
    pass 

このセットアップの問題点は、最初のクラスのデコレータは、第二のクラスの中に漏れているということです。

import pytest 
import sys 

def pytest_runtest_setup(item): 
    print "\n %s keywords: %s" % (item.getmodpath(), item.keywords) 
    skip_message = None 
    if 'windowsonly' in item.keywords and not sys.platform.startswith('win'): 
     skip_message = "Skipped: Windows only test" 

    if 'linuxonly' in item.keywords and not sys.platform.startswith('linux'): 
     skip_message = "Skipped: Linux only test" 

    if skip_message is not None: 
     print skip_message 
     pytest.skip(skip_message) 

を私は実行すると、この出力はマーキングが積み重ねるように見えることを示して設定します:

$ py.test --capture=no 
========================================== test session starts =========================================== 
platform linux2 -- Python 2.7.3 -- pytest-2.2.4 
collected 3 items 

test_cases.py 
TestLinuxOnlyLocal.test_base_test keywords: {'linuxonly': <MarkInfo 'linuxonly' args=() kwargs={}>, 'test_base_test': True} 
. 
TestWindowsOnly.test_base_test keywords: {'linuxonly': <MarkInfo 'linuxonly' args=() kwargs={}>, 'test_base_test': True, 'windowsonly': <MarkInfo 'windowsonly' args=() kwargs={}>} 
Skipped: Windows only test 
s 
TestEverywhere.test_base_test keywords: {'linuxonly': <MarkInfo 'linuxonly' args=() kwargs={}>, 'test_base_test': True, 'windowsonly': <MarkInfo 'windowsonly' args=() kwargs={}>} 
Skipped: Windows only test 
s 

================================== 1 passed, 2 skipped in 0.01 seconds =================================== 

だから私はそれが可能であるかを理解したい、次のように私はconftest.pyを作成するときこれらのマーキングがサブクラス間でリークすること、およびこれをどのように修正/解決することができるか(テストケースは基本クラスに存在するが、サブクラスは必要なプラットフォーム抽象化を設定する)

答えて

4

:あなたがしたいかもしれませんこのようなpytest.mark.skipif表現::

win32only = pytest.mark.skipif("sys.platform != 'win32'") 

を定義し、それにwin32の専用テストを飾る::

あなたは多分ちょうど::通常のテストクラスに「BaseTests」を回すことができる

class TestCrossPlatform: 
    def test_base_tests(...): 
     ... 

すなわち、任意の継承を避ける場合は0

@win32only 
def test_something(...): 

もう一つの問題はありますか?テストでフィクスチャを必要とする場合は、テストモジュールで定義し、テスト機能(クロスプラットフォームまたはプラットフォーム固有のもの)で受け入れることができます(pytest fixture docsを参照)。しかし、pytest-2.3シリーズ(特に2.4)にあるフィクスチャに関しては、特に多くの改良が施されているので、pytest-2.3.5を必ず使用してください。

9

pytestはPythonの他のテストフレームワーク(例:unittest)よりもテストにもっと機能指向のアプローチを採用しているため、クラスは主にテストを構成する方法として扱われます。

特に、クラス(またはモジュール)に適用されるマーカーはテスト関数自体に転送され、上書きされない派生クラスメソッドは基本クラスメソッドと同じオブジェクトなので、マーカーが適用されることを意味します基本クラスのメソッド

(技術的な詳細:現在、この_pytest.python.transfer_markers()で起こるが、それに依存しない)

代わりにクラスの継承の、プラットフォーム固有のテスト・セットアップをカプセル化するfixturesを使用することを検討してください。


簡単な解決策は、py.testは、アイテムのキーワードに即時に含むクラスを追加しているので、クラス名と比較するために次のようになります。ecatmurの良い答えに加えて

if 'TestWindowsOnly' in item.keywords and not sys.platform.startswith('win'): 
    skip_message = "Skipped: Windows only test" 

if 'TestLinuxOnly' in item.keywords and not sys.platform.startswith('linux'): 
    skip_message = "Skipped: Linux only test" 
+0

この問題の回避策はありますか?私は巨大な既存のテストスイートを持っていますが、私は上記のpy.test – dbn

+0

@dbwを使用しています。 – ecatmur

+0

これは私たちのケースではうまくいかないでしょう。私たちは、100以上の他のテストが異なるパネルに対していくつかの共通のテストを継承するという基礎テストをしています。これを行うpy.test-ishの方法に関する新しい質問を開きます。 – dbn

関連する問題