테스트를 통해 pytest 클래스를 올바르게 설정하고 분해하는 방법은 무엇입니까?


103

엔드 투 엔드 테스트를 위해 셀레늄을 사용 setup_class하고 있으며 사용 teardown_class방법 과 방법 을 얻을 수 없습니다 .

setup_class메서드에서 브라우저를 설정 한 다음 클래스 메서드로 정의 된 여러 테스트를 수행하고 마지막으로 teardown_class메서드 에서 브라우저를 종료해야합니다 .

그러나 논리적으로 그것은 나쁜 해결책처럼 보입니다. 사실 내 테스트는 클래스가 아니라 객체로 작동하기 때문입니다. self모든 테스트 메서드 내에서 매개 변수를 전달 하므로 개체의 var에 액세스 할 수 있습니다.

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____del__대신의 방법 setup_classteardown_class?

답변:


94

Fixture 마무리 / 해체 코드 실행 에 따르면 설정 및 해체에 대한 현재 모범 사례 yieldreturn다음 대신 사용하는 것입니다 .

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분해를 한 번 또는 여러 번 수행하는 함수로 메서드를 호출하는 것입니다.

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))

리소스가 필요한 모든 테스트 파일에 이것을 복사합니까?
Andy Hayden 2017

@AndyHayden 조명기를 작성하는 방법에 따라 필요한 모든 테스트 파일에 넣거나 conftest.py 파일 stackoverflow.com/questions/34466027/…
Everett Toews

2
그러나 이것은 수업 설정이 아닙니다. 클래스의 모든 테스트 메소드 전에 실행됩니다.
malhar

1
이 특별한 경우에는 테스트 메서드에서 매개 변수로 사용될 때만 실행됩니다. 예를 들어 resource매개 변수test_that_depends_on_resource(self, resource)
Everett 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_method및에 전달 teardown_method되지만 설정 / 해체 코드가 테스트 컨텍스트를 알 필요가없는 경우 무시할 수 있습니다. 자세한 정보는 여기 에서 찾을 수 있습니다 . .

또한 py.test의 fixtures 는 더 강력한 개념이므로 익숙해지는 것이 좋습니다 .


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)classmethods을.

그리고 각 테스트 케이스에 필요한 설정 및 해체를 위해 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는 각 테스트 케이스 방법의 각 단계입니다.
Kiran Vemuri

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그 객체가 될 수 있도록 고정 장치에서 참조 setuptorn 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/ 참조


이것은 문서에 나오는 것과 거의 동일합니다. 내가 문서에서 겪었던 문제는 컨텍스트를 이해하는 데 어려움이 있었다는 것입니다. self는 전통적으로 cls가 아니라 self라고 불립니다. 그래서 이것은 수업 자체의 맥락에서 이상하게 보였습니다. Kiran (위)은이 컨텍스트를 제공합니다.
Cognitiaclaeves

1
@Cognitiaclaeves "self는 전통적으로 cls가 아니라 self라고합니다." 예, self인스턴스 메서드에 사용됩니다. 첫 번째 인수는 메서드 작업이 발생하는 특정 개체 인스턴스 cls이고 @classmethods에는 바인딩됩니다. 클래스 (즉, 객체)의 인스턴스가 아닌 클래스.
code_dredd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.