2013-08-05 4 views
10

Ich verwende py.test 2.2.4 und mein Testfall ist wie folgt organisiert:Wie verwendet man @ pytest.mark mit Basisklassen?

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 

Das Problem bei diesem Aufbau ist, dass der Dekorateur der ersten Klasse in die zweite Klasse ist undicht. Wenn ich eine conftest.py wie folgt erstellen:

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) 

Wenn ich ausführen dies die Ausgabe zeigt, gesetzt, dass die Markierungen zu stapeln scheint:

$ 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 =================================== 

Deshalb möchte ich verstehen, wie es möglich ist, dass diese Markierungen zwischen den Unterklassen lecken und wie dies behoben werden kann (die Testfälle leben in der Basisklasse, aber die Unterklassen richten die notwendige Plattformabstraktion ein).

Antwort

4

Neben einer guten Antwort des ecatmur: Sie möchten vielleicht zu definieren einen pytest.mark.skipif Ausdruck wie folgt

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

:: und dann schmücken nur die win32-nur Tests mit ihm ::

Eine andere Frage ist, ob Sie vielleicht auch nur könnte die „BaseTests“ in eine normale Testklasse drehen ::

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

das heißt ein Erbteil vermeiden? Wenn Sie dann in Ihren Tests Fixtures benötigen, können Sie diese in Ihrem Testmodul definieren und in den Testfunktionen (plattform- oder plattformspezifisch) akzeptieren, siehe pytest fixture docs. Stellen Sie sicher, dass Sie pytest-2.3.5 verwenden, da es viele Verbesserungen speziell in Bezug auf die Geräte in der pytest-2.3 Serie gab (und weitere mit 2.4 kommen).

9

pytest nimmt einen mehr funktionsorientierten Testansatz als andere Python-Testframeworks (z. B. Komponententest), so dass Klassen hauptsächlich als eine Möglichkeit angesehen werden, Tests zu organisieren.

Insbesondere werden Marker, die auf Klassen (oder Module) angewendet werden, an die Testfunktionen selbst übertragen, und da eine nicht überschriebene abgeleitete Klassenmethode dasselbe Objekt wie die Basisklassenmethode ist, bedeutet dies, dass der Marker angewendet wird die Basisklassenmethode.

(Technisches Detail:. Zur Zeit dies geschieht in _pytest.python.transfer_markers(), aber verlassen Sie sich nicht auf dem)

Statt Klassenvererbung, betrachtet fixtures mit dem plattformspezifischen Testaufbau verkapseln.


Eine einfachere Lösung könnte gegen den Klassennamen zu vergleichen, da py.test die sofortige enthält Klasse Artikel Keywords ergänzt:

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

Gibt es Problemumgehungen für dieses Problem? Ich habe eine große vorhandene Testsuite, die ich migrieren möchte ot.test – dbn

+0

@dbw siehe oben. – ecatmur

+0

Das wird in unserem Fall nicht funktionieren - wir haben einen Basistest, von dem> 100 andere Tests erben, um einige allgemeine Tests für verschiedene Panels zu liefern. Ich werde eine neue Frage über den py.test-ish Weg öffnen, um dies zu tun. – dbn