오늘도 개발
pytest 사용법 1) 설정, fixture, parametrize 본문
0. pytest를 사용하는 이유
django unittest보다 간결하게 작성할 수 있다.
필수로 클래스를 정의할 필요도 없고, assert를 사용할 때 unittest.TestCase의 어느 assert를 사용해야 할 지 고민할 필요도 없다.
assert만 사용하면 되기 때문이다. (이에 따른 장단점이 있기 때문에 unittest가 pytest보다 더 나은 경우도 있다.)
1. 기본적인 사용 방법
<설치>
pip pytest
<pytest.ini>
pytest는 기본적으로 test_*.py를 찾아 실행한다.
django 앱 내 tests.py의 테스트코드를 실행시키려면 manage.py와 같은 위치에 pytest.ini 파일을 만들어 설정해주어야 한다.
[pytest]
DJANGO_SETTINGS_MODULE = testcode.settings #프로젝트 세팅
python_files = tests.py test_*.py *_tests.py
testpaths = arithmatic # 테스트할 앱 이름
addopts = --nomigrations
<arithmatic/tests.py>
# 아무것도 import하지 않아도 작동한다
def test_pass():
assert True
def test_fail():
assert False
<실행>
# 모든 테스트 실행
pytest
# 특정 파일의 모든 테스트 실행
pytest 경로
# 특정 테스트만 실행
pytest 경로::함수명
# 특정 테스트만 실행 (테스트가 클래스 속에 있는 경우)
pytest 경로::클래스명::함수명
# pytest arithmatic/tests.py::TestSum::test_add
2. fixture
unittest에서는 setUp()에 데이터 생성 로직을 작성하고 tearDown()에 삭제 로직을 작성해서
매 테스트마다 setUp()과 tearDown()로 데이터가 생성 후 삭제되도록 만들 수 있다.
pytest의 fixture는 이와 비슷한 기능이다.
setUp()과 tearDown()은 맨 처음에 정의하면 암묵적으로 테스트마다 실행되지만,
fixture는 정의 후 테스트마다 사용할 fixture를 명시적인 인수로 넣어주어야 한다. (=> 가독성 높아짐)
<arithmatic/views.py>
def add(num1, num2):
return num1 + num2
<arithmatic/tests.py>
# 사용할 테스트 DB 명시
@pytest.mark.django_db
class TestSum: # 클래스명은 Test로 시작해야 함
@pytest.fixture
def first_num(self):
return 1
@pytest.fixture
def second_num(self):
return 2
def test_add(self, first_num, second_num): # 사용할 fixture의 함수명을 인수에 넣는다.
print('testing..!') # pytest로 실행하는 경우 Fail인 경우에만 콘솔에서 바로 확인할 수 있다.
assert add(first_num, second_num) == 3
def test_square(self, second_num):
assert square(second_num) == 4
픽스쳐를 제너레이터 형태로 만들어서 사용할 수도 있다.
import pytest
@pytest.fixture
def make_user():
def _make_user(first_name, last_name):
return {'first_name' : first_name, 'last_name' : last_name}
return _make_user
def test_greet_user(make_user):
lisa = make_user("Lisa", "Simpson")
bart = make_user("Bart", "Simpson")
assert lisa['last_name'] == bart['last_name']
3. parametrize
@pytest.mark.parametrize로 테스트 여러 번 돌리기
다음 경우 테스트가 두 번 돌아간다.
1. User 인스턴스(snoopy)를 사용한 테스트가 돌아감
2. User 인스턴스(garfield)를 사용한 테스트가 돌아감
class User:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
# Snoopy, Garfield User 인스턴스를 만들고 user라고 부르겠다는 뜻
@pytest.mark.parametrize('user', [
User(first_name='Snoopy', last_name='Woof'),
User(first_name='Garfield', last_name='Meow'),])
def test_greet_user(user):
if user.first_name == 'Snoopy':
assert f'{user.first_name} {user.last_name}' == 'Snoopy Woof'
else:
assert f'{user.first_name} {user.last_name}' == 'Garfield Meow'
@pytest.mark.parametrize(indirect=True)로 픽스쳐 반환값의 일부만 대체하기
indirect=True로 설정한 경우 fixture 함수의 body도 실행이 된다.
위의 경우와 달리 픽스쳐의 인수는 User 인스턴스의 일부만 대체한다.
class User:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@pytest.fixture
def user(request): # request 키워드를 써야 함
return User(
first_name=request.param, # param 키워드를 써야 함
last_name = 'Simpson'
)
@pytest.mark.parametrize('user', ['Lisa', 'Bart'], indirect=True)
def test_greet_user(user):
if user.first_name == 'Lisa':
assert f'{user.first_name} {user.last_name}' == 'Lisa Simpson'
else:
assert f'{user.first_name} {user.last_name}' == 'Bart Simpson'
'웹 프로그래밍 > Python3' 카테고리의 다른 글
| all(), any() (0) | 2023.02.18 |
|---|---|
| pytest 사용법 2) mock (0) | 2023.01.19 |
| pyenv와 pyenv-virtualenv (0) | 2023.01.03 |
| setdefault와 defaultdict (0) | 2022.12.23 |
| Python의 GC(Garbage Collection) (0) | 2022.10.31 |