코드로 우주평화

@pytest.fixture 로 test 데이터 세팅하기 본문

나는 이렇게 학습한다/Debug

@pytest.fixture 로 test 데이터 세팅하기

daco2020 2022. 4. 14. 19:44
반응형

pytest.fixture 는 왜 사용할까?

 

테스트 코드를 작성하다보면 ‘클라이언트’나 ‘토큰’, ‘객체’ 등이 필요할 수 있습니다.

 

보통은 setup 이나 teardown 등으로 데이터를 세팅할 수 있지만 pytest에는 fixture 데코레이터를 통해 필요한 데이터를 세팅하고 어떤 테스트 함수든지 재활용할 수 있습니다.

 

 

테스트 코드 예시

 

아래는 로그인 api를 테스트 하는 함수입니다.

# test_login.py

def test_login_api(client, create_user):
    data = {
        "email": "test@test.com",
        "password": "password",
    }

    r = client.post("/api/v1/login", json=data)

    r_message = r.json()
    assert r.status_code == 200
    assert r_message.get("access_token")
    assert r_message.get("refresh_token")

test_login_api함수는 ‘client’, ‘create_user’ 라는 두 개의 인자를 받고 있습니다.

 

client는 url요청에 필요한 것이고

create_user는 테스트 전에 생성된 유저를 뜻합니다.

(유저가 생성되어야 로그인을 할 수 있으므로)

 

 

실제 테스트를 돌려보니 성공했다는 메시지가 나옵니다.

============================================================================================= test session starts ==============================================================================================
platform darwin -- Python 3.10.0, pytest-7.1.1, pluggy-1.0.0
rootdir: /Users/daco/alphaprime/portfolio-toy-project-uckim
plugins: anyio-3.5.0
collecting ... SECRET_KEY
collected 1 item                                                                                                                                                                                               

ap_toy/tests/api/test_login.py .                                                                                                                                                                         [100%]

============================================================================================== 1 passed in 0.35s ===============================================================================================

 

 

그런데 이상합니다.

 

위의 코드를 다시 살펴보면 import가 명시되어있지 않다는 것을 알 수 있습니다.

test_login_api 함수의 인자는 도대체 어디에서 온걸까요?

 

 

답은 @pytest.fixture

 

쉬운 이해를 위해 create_user의 경우만 살펴보겠습니다.

 

코드는 다음과 같습니다.

# conftest.py

import pytest

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from .config import settings
from .models import User

db_engine = create_engine(settings.POSTGRES_DSN)
session = sessionmaker(autocommit=False, autoflush=False, bind=db_engine)

@pytest.fixture
def create_user():
    user = User(
        nickname="test",
        email="test@test.com",
        password="1q2w3e4r",
    )
    db = session()
    db.add(user)
    db.commit()

 

 

create_user 함수 위에 pytest.fixture 데코레이터가 작성된 것을 볼 수 있습니다.

@pytest.fixture
def create_user():

 

이제 이 함수는 테스트 함수에 인자로 넣을 수 있는 함수가 됩니다.

 

 

다시 테스트 코드로 돌아가 보면 인자로 create_user가 있는 것을 볼 수 있습니다.

# test_login.py

def test_login_api(client, create_user):

이렇게 들어간 create_user 함수는 해당 테스트 함수가 실행될 때 먼저 실행됩니다.

 

유저가 생성되었으니 이제 로그인 테스트를 정상적으로 수행할 수 있습니다.

 

 

마무리

 

@pytest.fixture를 사용하면 번거롭게 데이터 세팅을 여러번 할 필요가 없습니다.

 

한번 작성해두면 테스트 클래스나 모듈별로 setup, teardown을 작성하지 않아도 되므로 테스트를 좀 더 수월하게 작성할 수 있습니다.

 

이 외에도 데이터베이스를 생성하고 초기화하는 등의 일련의 과정을 @pytest.fixtur로 구현할 수 있습니다.

 

 

자세한 사용법은 공식문서를 참고하시기 바랍니다!

 

pytest fixtures: explicit, modular, scalable — pytest documentation

Software test fixtures initialize test functions. They provide a fixed baseline so that tests execute reliably and produce consistent, repeatable, results. Initialization may setup services, state, or other operating environments. These are accessed by tes

docs.pytest.org

 

 

 

 

반응형