테스트 코드들에서 공통으로 사용되는 함수 또는 코드들을 작성할 떄 유용.
테스트의 기반이 되는 기초 환경 구성에도 유용.
#conftest.py 라는 명칭으로 작성하면, 다른 test 파일들이 알아서 참조하게 됨
import pytest
@pytest.fixture #fixture로 선언할 코드들을 아래에 작성
def supply_AA_BB_CC():
aa=25
bb=35
cc=45
return [aa,bb,cc]
#test_basic_fixture.py
#전혀 다른 파일에서도 fixture를 공유하기 때문에 위에서 작성한 함수를 바로 사용할 수 있다.
import pytest
@pytest.fixture
def test_comparewithAA(supply_AA_BB_CC):
zz=35
assert supply_AA_BB_CC[0] == zz, "aa and zz comparison failed"
: pytest test_basic_fixture.py
: -> aa and zz comparison failed
pytest를 실행하면 정상적으로 supply_AA_BB_CC 함수를 인식하고, 테스트 통과 실패에 따른 메시지가 나타날 것이다.
마킹이 된 것들은 마크별로 테스트 실행을 구분지을 수 있다.
import pytest
@pytest.mark.set1 #set1이라는 이름으로 마킹
def test_fil1_method1():
x = 5
y = 6
assert x + 1 === y, "test failed"
assert x == y, f"test failed because x={x} y={y}!"
#run pytest with marks
# -m 옵션과 마크 이름을 지정하여 실행
: pytest -m set1
다수의 argumnets 세트로 테스트를 실행할 때 사용한다.
import pytest
@pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
'''
"input1, input2, output"은 해당 위치의 변수값들과 1대1로 매치되는 변수명
1번째 argument는 list 형태로 각각의 튜플 원소를 가지는데, 각각의 원소에 대하여 순회하며 test를 실행하게 됨
ex) 첫번째 테스트 : input1 = 5, input2 = 5, output = 10
두번째 테스트 : input1 = 3, input2 = 5, output = 12
'''
def test_add(input1, input2, output):
assert input1+input2 == output, "failed"
테스트를 실행하면 1번째 argumnet로 실행한 테스트에서 fail 되는 것을 확인할 수 있다.
test_addition.py::test_add[5-5-10] PASSED
test_addition.py::test_add[3-5-12] FAILED
============================================== FAILURES ==============================================
__________________________________________ test_add[3-5-12] __________________________________________
input1 = 3, input2 = 5, output = 12
@pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
def test_add(input1, input2, output):
> assert input1+input2 == output,"failed"
E AssertionError: failed
E assert (3 + 5) == 12
test_addition.py:5: AssertionError
특정 상황에서는 어떤 테스트를 실행하고 싶지 않거나, 무관한 테스트를 제외하고 싶을 수 있다.
그럴 때에 xfail이나 skip을 사용한다.
xfail한 테스트는 실행은 되지만 fail 또는 pass에 집계되지 않는다.
skip한 테스트는 실행조차 되지 않는다.
import pytest
@pytest.mark.skip
def test_add_1():
assert 100+200 == 400, "failed"
@pytest.mark.skip
def test_add_2():
assert 100+200 == 300, "failed"
@pytest.mark.xfail
def test_add_3():
assert 15+13 == 28, "failed"
@pytest.mark.xfail
def test_add_4():
assert 15+13 == 100,"failed"
def test_add_5():
assert 3+2 == 5, "failed"
def test_add_6():
assert 3+2 == 6, "failed"
테스트를 실행하면 아래와 같은 결과로 나타난다.
test_addition.py::test_add_1 SKIPPED
test_addition.py::test_add_2 SKIPPED
test_addition.py::test_add_3 XPASS
test_addition.py::test_add_4 xfail
test_addition.py::test_add_5 PASSED
test_addition.py::test_add_6 FAILED
============================================== FAILURES ==============================================
_____________________________________________ test_add_6 _____________________________________________
def test_add_6():
> assert 3+2 == 6,"failed"
E AssertionError: failed
E assert (3 + 2) == 6
test_addition.py:24: AssertionError
================ 1 failed, 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.07 seconds =================
테스트 결과를 XML 형식으로 생성할 수도 있다.
#test1_sample1.py의 테스트 결과를 xml 파일로 뽑아보자
: pytest test_sample1.py -v --junitxml="result.xml" #파일명은 result.xml로 임의 지정했다
테스트가 끝나면 result.xml이라는 파일이 아래와 같은 내용을 생성된다.
<?xml version="1.0" encoding="utf-8"?><testsuites><testsuite errors="0" failures="1" hostname="gimsang-us-MacBook-Pro.local" name="pytest" skipped="0" tests="2" time="0.037" timestamp="2020-08-13T16:24:09.430519"><testcase classname="test_sample1" file="test_sample1.py" line="1" name="test_file1_method1" time="0.001"><failure message="AssertionError: test failed because x=5 y=6
assert 5 == 6
+5
-6">@pytest.mark.set1
def test_file1_method1():
x=5
y=6
assert x+1 == y, "test failed"
> assert x == y, "test failed because x=" + str(x) + " y=" + str(y)
E AssertionError: test failed because x=5 y=6
E assert 5 == 6
E +5
E -6
test_sample1.py:7: AssertionError</failure></testcase><testcase classname="test_sample1" file="test_sample1.py" line="7" name="test_fil1_method2" time="0.001"></testcase></testsuite></testsuites>
앞서 알아본 방법들을 활용하여 API를 테스트해본다.
테스트에 사용할 샘플 API는 샘플API를 사용한다.
(단, 공통으로 사용하기 위하여 fixture단에서 선언해준다.)
#confest.py
import pytest
@pytest.fixture
def supply_url():
return "https://reqres.in/api"
해당 API의 호출과 관련하여 실제로 테스트할 코드는 아래에서 작성한다.
#test_list.user.py
import pytest
import requests
import json
@pytest.fixture
@pytest.mark.parametrize("userid, firstname",[(1, "George"), (2, "janet")])
def test_list_valid_user(supply_url, userid, firstname):
url = supply_url + "/users/" + str(userid)
resp = requests.get(url)
j = json.loads(resp.text)
assert resp.status_code == 200, resp.text
assert j['data']['id'] == userid, resp.text
assert j['data']['first_name'] == firstname, resp.text
def test_list_invaliduser(supply_url):
url = supply_url + "/users/50"
resp = requests.get(url)
assert resp.status_code == 404, resp.text
#test_login_user.py
import pytest
import requests
import json
def test_login_valid(supply_url):
url = supply_url + "/login"
data = {'email': 'test@test.com', 'password': 'something'}
resp = requests.post(url, data=data)
j = json.loads(resp.text)
assert resp.status_code == 400, resp.text
assert j['error'] == 'Missing password', resp.text
def test_login_no_email(supply_url):
url = supply_url + "/login"
data = {}
resp = requests.post(url, data=data)
j = json.loads(resp.text)
assert resp.status_code == 400, resp.text
assert j['error'] == 'Missing email or username', resp.text
requests 모듈을 사용하여 실제로 호출 및 응답받은 값을 통하여 테스트를 실행하게 된다.
[python] collections.Counter를 사용하여 중복 체크하기 (0) | 2021.01.16 |
---|---|
AWS EC2에 pyenv로 python 설치하기 (0) | 2020.07.01 |
Django - intro (0) | 2019.07.23 |
dictionary + iteration 딕셔너리와 반복문 (0) | 2019.07.22 |
PIP와 Virtualenv (0) | 2019.07.22 |
댓글 영역