기능을 개발하고 나서 제대로 돌아가는지 매번 수동으로 API를 쏠수 없으니 Unit Test를 하여 각 기능들이 제대로 돌아가는지 테스트를 해야합니다.
웹브라우저를 통해서 웹사이트를 실제로 접속하고 UI에 직접 입력하고 클릭하는 등을 통해서 기능을 정상적으로 작동하고 화면이 정상적으로 작동하는지 테스트 해보는 방식
아래는 웹 UI test하는 툴입니다.
각 기능(모듈)을 통합하는 과정에서 모듈간 호환성의 문제를 찾아내기 위해 수행되는 테스트
각각 기능 하나에 대해서 코드 테스트를 합니다.
python3에서 uniittest라는 모듈이 탑재되어 있지만 좀더 쓰기 편한 pytest를 사용합니다.
# test_minitter.py
import pytest
import bcrypt
import json
import config
import sys
from sqlalchemy import create_engine, text
sys.path.append('../')
from app import create_app
database = create_engine(config.test_config['DB_URL'], encoding='utf-8', max_overflow=0)
@pytest.fixture
def api():
app = create_app(config.test_config)
app.config['TESTING'] = True
api = app.test_client()
return api
def setup_function():
hashed_password = bcrypt.hashpw(b"test password", bcrypt.gensalt())
new_users = [
{
"id": 1,
"name": "test1",
"email": "test1@test.com",
"profile": "test1 profile",
"hashed_password": hashed_password
},
{
"id": 2,
"name": "test2",
"email": "test2@test.com",
"profile": "test2 profile",
"hashed_password": hashed_password
}
]
database.execute(text("""
INSERT INTO users (
id,
name,
email,
profile,
hashed_password
) VALUES (
:id,
:name,
:email,
:profile,
:hashed_password
)
"""), new_users)
database.execute(text("""
INSERT INTO tweets (
user_id,
tweet
) VALUES (
2,
"Hello World!"
)
"""))
def teardown_function():
database.execute(text("SET FOREIGN_KEY_CHECKS=0"))
database.execute(text("TRUNCATE users"))
database.execute(text("TRUNCATE tweets"))
database.execute(text("TRUNCATE users_follow_list"))
database.execute(text("SET FOREIGN_KEY_CHECKS=1"))
def test_ping(api):
resp = api.get('/ping')
assert b'pong' in resp.data
def test_login(api):
resp = api.post(
'/login',
data = json.dumps({'email': 'test1@test.com', 'password': 'test password'}),
content_type = 'application/json'
)
assert b"access_token" in resp.data
def test_unauthorized(api):
resp = api.post(
'/tweet',
data = json.dumps({'tweet': 'Hello World!'}),
content_type = 'application/json'
)
assert resp.status_code == 401
resp = api.post(
'/follow',
data = json.dumps({'follow': 2}),
content_type = 'application/json'
)
assert resp.status_code == 401
resp = api.post(
'/unfollow',
data = json.dumps({'unfollow': 2}),
content_type = 'application/json'
)
assert resp.status_code == 401
def test_tweet(api):
resp = api.post(
'/login',
data = json.dumps({'email': 'test1@test.com', 'password': 'test password'}),
content_type = 'application/json'
)
resp_json = json.loads(resp.data.decode('utf-8'))
access_token = resp_json['access_token']
resp = api.post(
'/tweet',
data = json.dumps({'tweet': "Hello World!"}),
content_type = 'application/json',
headers = {'Authorization': access_token}
)
assert resp.status_code == 200
resp = api.get(f'/timeline/1')
tweets = json.loads(resp.data.decode('utf-8'))
assert resp.status_code == 200
assert tweets == {
"user_id": 1,
"timeline": [
{
"user_id": 1,
"tweet": "Hello World!"
}
]
}
def test_follow(api):
resp = api.post(
'/login',
data = json.dumps({'email': 'test1@test.com', 'password': 'test password'}),
content_type = 'application/json'
)
resp_json = json.loads(resp.data.decode('utf-8'))
access_token = resp_json['access_token']
resp = api.get(f'/timeline/1')
tweets = json.loads(resp.data.decode('utf-8'))
assert resp.status_code ==200
assert tweets == {
'user_id': 1,
'timeline': []
}
resp = api.post(
'/follow',
data = json.dumps({'id': 1, 'follow': 2}),
content_type = 'application/json',
headers = {'Authorization': access_token}
)
assert resp.status_code == 200
resp = api.get(f'/timeline/1')
tweets = json.loads(resp.data.decode('utf-8'))
assert resp.status_code == 200
assert tweets == {
'user_id': 1,
'timeline' : [
{
'user_id': 2,
'tweet': 'Hello World!'
}
]
}
def test_unfollow(api):
resp = api.post(
'/login',
data = json.dumps({'email': 'test1@test.com', 'password': 'test password'}),
content_type = 'application/json'
)
resp_json = json.loads(resp.data.decode('utf-8'))
access_token = resp_json['access_token']
resp = api.post(
'/follow',
data = json.dumps({'id': 1, 'follow': 2}),
content_type = 'application/json',
headers = {'Authorization': access_token}
)
assert resp.status_code == 200
resp = api.get(f'/timeline/1')
tweets = json.loads(resp.data.decode('utf-8'))
assert resp.status_code == 200
assert tweets == {
"user_id" : 1,
"timeline": [
{
"user_id": 2,
"tweet": "Hello World!"
}
]
}
resp = api.post(
'/unfollow',
data = json.dumps({'id': 1, 'unfollow': 2}),
content_type = 'application/json',
headers = {'Authorization': access_token}
)
assert resp.status_code == 200
resp = api.get(f'/timeline/1')
tweets = json.loads(resp.data.decode('utf-8'))
assert resp.status_code == 200
assert tweets == {
"user_id": 1,
"timeline": []
}
$> pytest -p no:warnings -vv -s
================================================= test session starts ==================================================
platform linux -- Python 3.6.5, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /project/huggingfaceAPI/venv/bin/python
cachedir: .pytest_cache
rootdir: /project/huggingfaceAPI/test
collected 6 items
test_minitter.py::test_ping PASSED
test_minitter.py::test_login PASSED
test_minitter.py::test_unauthorized PASSED
test_minitter.py::test_tweet PASSED
test_minitter.py::test_follow PASSED
test_minitter.py::test_unfollow PASSED
================================================== 6 passed in 11.87s ==================================================
잘보고 있습니다~!! 책으로 하는데 너무 에러가 많아서 에러 고치느라 애먹었는데 글 보며 어느정도 해결했네요! 다음편도 부탁드립니다~!!