Fixture
테스팅을 하는데 있어서 필요한 조건들을 미리 준비해놓은 리소스 또는 코드
예) 특정 조건으로 구성된 데이터베이스, 데이터 셋
Fixture 생성 예시
@pytest.fixture 데코레이터를 함수에 붙여 fixture로 만들 수 있다.
import pytest
@pytest.fixture
def my_fruits():
return ["apple", "banana", "grape", "orange"]
Fixture를 사용하지 않는 경우
def test1():
fruits = ["apple", "banana", "grape", "orange"]
assert len(fruits) == 4
def test2():
fruits = ["apple", "banana", "grape", "orange"]
assert "apple" in fruits
Fixture를 사용하는 경우
fixture를 사용할 때는 fixture의 함수명을 인자로 받아와서 사용한다.
import pytest
@pytest.fixture
def my_fruits():
return ["apple", "banana", "grape", "orange"]
def test1(my_fruits):
assert len(my_fruits) == 4
def test2(my_fruits):
assert "apple" in my_fruits
Fixture의 특징
1. fixture는 다른 fixture를 사용할 수 있다.
import pytest
@pytest.fixture
def my_fruit():
return "apple"
@pytest.fixture
def fruit_basket(my_fruit):
return [my_fruit, "banana", "orange"]
def test(my_fruit, fruit_basket):
assert myfruit in fruit_basket
2. fixture는 재사용이 가능하다.
서로 다른 테스트 함수에서 같은 fixture를 독립적으로 사용할 수 있다.
import pytest
@pytest.fixture
def fruit_basket():
return ["apple", "banana", "orange"]
def test1(fruit_basket):
fruit_basket.append("kiwi")
assert fruit_basket == ["apple", "banana", "orange", "kiwi"]
def test2(fruit_basket):
fruit_basket.append("melon")
assert fruit_basket == ["apple", "banana", "orange", "melon"]
fruit_basket fixture는 각 테스트에서 호출될 때마다 실행되면서 리스트 객체의 복사본을 넘겨주고 있다.
3. fixture의 반환값은 같은 테스트 내에서 캐싱된다.
import pytest
@pytest.fixture
def my_fruit():
return "apple"
@pytest.fixture
def fruit_basket():
return []
@pytest.fixture
def append_fruit(my_fruit, fruit_basket):
return fruit_basket.append(my_fruit)
def test_fruit(my_fruit, fruit_basket, append_fruit):
assert fruit_basket == [my_fruit] # ["apple"] == ["apple"]
위 코드를 실행하면 어떤 결과가 나올까? fruit_basket fixture이 빈 리스트를 반환하기 때문에 테스트 실패가 나올 것이라고 생각할 수 있겠지만, 결과는 테스트 성공이다.
>> pytest test.py
=================================================== test session starts ===================================================
platform darwin -- Python 3.9.13, pytest-7.3.1, pluggy-1.0.0
rootdir: /Users/sangwon/Desktop
plugins: anyio-3.5.0
collected 1 item
test.py . [100%]
==================================================== 1 passed in 0.01s ====================================================
위 코드에서 하나의 테스트 함수(test_fruit)에서 fruit_basket fixture는 2번 호출된다. append_fruit fixture에서 fruit_basket fixture를 호출한 뒤, my_fruit을 추가한 값을 캐싱하고 있기 때문에, test_fruit 함수에서 fruit_basket의 값은 [”apple”]을 갖는다.
반면 아래 코드의 테스트는 실패한다.
import pytest
@pytest.fixture
def my_fruit():
return "apple"
@pytest.fixture
def fruit_basket():
return []
@pytest.fixture
def append_fruit(my_fruit, fruit_basket):
return fruit_basket.append(my_fruit)
def test(my_fruit, fruit_basket): # append_fruit을 호출하지 않음
assert fruit_basket == [my_fruit] # AssertionError: assert [] == ["apple"]
4. autouse fixture
해당 fixture를 호출하는 함수가 없더라도 자동으로 실행되도록 하는 옵션이다.
fixture의 데코레이터에 autouse=True 인자를 넣어 autouse fixture로 만들 수 있다.
import pytest
@pytest.fixture
def my_fruit():
return "apple"
@pytest.fixture
def fruit_basket():
return []
# autouse fixture
@pytest.fixture(autouse=True)
def append_fruit(my_fruit, fruit_basket):
return fruit_basket.append(my_fruit)
def test(my_fruit, fruit_basket):
assert fruit_basket == [my_fruit] # ["apple"] == ["apple"]
5. scope
fixture는 테스트 함수가 호출하여 생성되고 나면 지정된 범위 내에서는 같은 fixture를 공유한다.
scope로 가질 수 있는 값은 아래와 같다.
- function: 기본 값, 테스트가 끝나고 나면 fixture가 삭제된다.
- class: class의 마지막 테스트가 끝나고 나면 fixture가 삭제된다.
- module: 모듈 내의 마지막 테스트가 끝나고 나면 fixture가 삭제된다.
- package: 패키지 내의 마지막 테스트가 끝나고 나면 fixture가 삭제된다.
- session: 테스트 세션이 끝나고 나면 fixture가 삭제된다.
# scope 사용 예시
@pytest.fixture(scope="module")
6. yield
fixture로 선언된 함수는 return문으로 값을 전달할 수 있다. 이 때, 데이터를 정리하기 위한 목적으로 return 대신 yield를 사용할 수 있다.
함수에서 return이 실행되면 함수가 종료되기 때문에, yield를 대신 사용하여 yield문 뒤에 teardown code를 작성하면 테스트가 종료된 이후에 데이터를 정리할 수 있다.
from selenium.webdriver import Chrome
@pytest.fixture
def driver():
driver = Chrome()
yield driver
# teardown code
driver.quit()
7. conftest.py
conftest.py 파일에 정의한 fixture는 같은 디렉토리에 위치한 여러 테스트 모듈에서 import 없이 사용할 수 있다.
# test/conftest.py
import pytest
@pytest.fixture
def my_fruit():
return "apple"
@pytest.fixture
def fruit_basket():
return []
@pytest.fixture(autouse=True)
def append_fruit(my_fruit, fruit_basket):
return fruit_basket.append(my_fruit)
# test/fruit_test.py
def test_fruit_sangwon(my_fruit, fruit_basket):
assert fruit_basket == [my_fruit]
'Backend > pytest' 카테고리의 다른 글
[pytest] 테스트 코드에서 명령행 인자 전달하는 방법 (feat. argparse) (0) | 2023.06.15 |
---|---|
[pytest] 파이썬 테스팅을 위한 pytest 사용법 (0) | 2023.06.09 |