앞 단계 참조 링크:
- 상태 코드: 2024.03.26 - [Web 개발/FAST API (인프런 강의 내용)] - 1 FastAPI 알아보기
- 프로젝트 소개 및 환경 구축: 2024.04.05 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습1 GET API 전체조회
- 1 실습1 GET API ToDo 전체 조회: 2024.04.05 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습1 GET API 전체조회
- 1 실습2 GET API ToDo 단일 조회: 2024.04.09 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습2 GET API 단일조회
- 1 실습3 POST API ToDo 생성: 2024.04.15 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습3 POST API todo 생성
- 1 실습4 PATCH API ToDo 수정: 2024.04.16 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습4 PATCH API todo 수정
- 1 실습5 DELETE API ToDo 삭제: 2024.04.17 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습5 DELETE API todo 삭제
- 1 실습6 ERROR 처리: 2024.04.18 - [Web 개발/FAST API (인프런 강의 내용)] - 1 실습6 ERROR 처리
- 2 데이터베이스: 2024.04.24 - [Web 개발/FAST API (인프런 강의 내용)] - 2 데이터베이스
- 2 실습1 MySQL 컨테이너 실행 (docker): 2024.04.24 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습1 MySQL 컨테이너 실행 (docker)
- 2 실습2 MySQL 접속 및 사용: 2024.04.25 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습2 MySQL 접속 및 사용
- 2 실습3 데이터베이스 연결: 2024.04.25 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습3 데이터베이스 연결
- 2 실습4 ORM 모델링: 2024.05.02 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습4 ORM 모델링
- 2 실습5 ORM GET 전체조회 API: 2024.05.03 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습5 ORM 적용 - GET 전체조회 API
- 2 실습6 ORM HTTP Response 처리: 2024.05.10 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습6 ORM 적용 - HTTP Response 처리
- 2 실습7 ORM GET 단일조회 API: 2024.05.14 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습7 ORM 적용 - GET 단일조회 API
- 2 실습8 ORM Refactoring: 2024.06.01 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습8 ORM 적용 - Refactoring
- 2 실습9 ORM POST API: 2024.06.01 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습9 ORM 적용 - POST API
- 2 실습10 ORM PATCH API: 2024.06.01 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습10 ORM 적용 - PATCH API
- 2 실습11 ORM DELETE API: 2024.06.01 - [Web 개발/FAST API (인프런 강의 내용)] - 2 실습11 ORM 적용 - DELETE API
- 3 테스트 코드 PyTest: 2024.06.01 - [Web 개발/FAST API (인프런 강의 내용)] - 3 테스트 코드 PyTest
00 개요
- 목적: PyTest (테스트 코드)를 이용해 ToDo API에 테스트 코드 적용 실습 진행
- 설치해야되는 libraries: pytest, httpx
- 먼저 해야할 것들이 있음!
1. main.py 수정하기
- todo_data 딕셔너리 삭제 (실제 DB를 사용하므로 이 딕셔너리는 더 이상 사용하지 않을 것이기 때문)
2. 테스트 코드 작성 및 PyTest 사용 시 필수 사항
- Python Package 및 테스트 코드 작성 시 패키지명, 모듈명, 함수명의 앞부분이 'test'로 시작해야됨
- 이유: pytest가 'test'라는 패키지/모듈/함수를 우선적으로 탐색하여 테스트 코드로 인식하여 검증을 할 수 있게됨
01 ToDo에 PyTest 적용하기
1. main.py 확인
- 테스트 코드를 적용할 API 확인하기:
# /c/Users/관리자/Desktop/projects/todos/src/main.py 내용
...
# 첫 화면 API
@app.get("/")
def health_check_handler():
return {"ping": "pong"}
...
- 정보:
- get 요청 사용
- 경로: "/"
- 함수명: 'health_check'
- 정상적인 반환값: {'ping': 'pong'}
2. 필요한 library 설치: pytest, httpx
- pytest: 테스트 코드 작성을 위한 library
- httpx: FastAPI에서 test client라는 기능 사용 시 test client에서 내부적으로 사용하는 library
# 가상화 환경 활성화 후 진행 - 현재 경로: /c/Users/관리자/Desktop/projects/todos
$ . Scripts/activate
(todos)
$ pip install --upgrade pytest httpx
- 하는 김에 pip도 upgrade해줌
3. Python Package 생성
- src 디렉토리 안에 'tests'라는 이름의 Python Package 생성하기
- Python Package란:
- Python Package 생성 시 __init__.py (빈 파일)이 생성됨
- PyTest 사용 시 경로를 찾을 때 반드시 Python 모듈인 경우에만 경로를 찿을 수 있어서 tests라는 Python Package 안에 테스트 파일들을 생성하면 PyTest가 자동으로 해당 파일들을 테스트로 인지하고 실행할 것
- 원리: tests라는 Python Package 안에 __init__.py가 있어서 PyTest가 정상적으로 경로 탐색이 가능하게 됨
4. test_main.py (테스트 코드 파일) 작성
- 'test_main.py' 테스트 파일 생성
- 반드시 'test'라고 파일명을 시작해야 됨
from fastapi.testclient import TestClient
from main import app
client = TestClient(app=app)
def test_health_check(): # 적용할 함수명과 이름을 같게 해주면 편리함 (i.e, 'health_check')
response = client.get("/")
assert response.status_code == 200
asset response.json() == {'ping': 'pong'}
- 설명:
- from fastapi.testclient import TestClient
- from main import app
- client = TestClient(app=app)
- client라는 객체 생성
- TestClient()에 app=app을 인자로 전달 시 main.py 안에 있는 app이 하나의 TestClient가 됨
- 이 TestClient를 이용하여 이 클라이언트에 어떤 API 요청을 보내는 형태로 테스트 코드를 작성할 것
- def test_health_check():
- response = client.get("/")
- 앞서 API를 매핑했던 것과 같이 클라이언트 객체에 .get() 메소드를 이용하여 첫 번째 인자로 경로("/") 지정 시 TestClient에 "/" path로 get 요청이 가게 됨
- assert response.status_code == 200
- asset response.json() == {'ping': 'pong'}
- assert문으로 검증하는 것
- response = client.get("/")
- assert문이란 (참조: 2024.07.26 - [Python] - assert (파이썬 키워드) )
- 결과가 True라면 넘어가고 (아무것도 안함) False라면 AssertionError 발생시켜 프로그램을 중단시킴
5. 테스트 코드 실행
- Note: tests가 있는 src 경로에서 pytest 명령어를 실행 필수
$ pytest
# 터미널 출력 내용
======================= test session starts =============================
platform win32 -- Python 3.12.1, pytest-8.3.2, pluggy-1.5.0
rootdir: C:\Users\관리자\Desktop\projects\todos\src
plugins: anyio-4.2.0
collected 1 item
tests\test_main.py . [100%]
======================== warnings summary ================================
..\..\..\..\AppData\Local\Programs\Python\Python312\Lib\site-packages\pydantic\_internal\_config.py:272
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\pydantic\_internal\_config.py:272: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.6/migration/
warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=================== 1 passed, 1 warning in 1.90s =========================
- 위의 명령어 실행 시 pytest가 src 디렉토리에서 테스트 코드들을 쭉 검색 하고 tests라는 Python Package 안에 있는 test로 시작하는 test_main.py를 테스트 파일로 인식하고 그 안에 test로 시작하는 test_health_check() 함수를 테스트 코드로 인식하여 해당 함수를 동작시킴
- 위 내용은 tests\test_main.py가 실행되었다는 것과 1개의 테스트 코드가 정상적으로 통과했다는 것
- 한 번 테스트 코드 실행 시 src 디렉토리 안에 .pytest_cache라는 디렉토리가 자동으로 생성됨
- pytest가 테스트 코드들을 탐색 및 실행 과정에서 여러가지 경로, 결과값 등에 대한 정보를 담아서 pytest가 관리해주고 이용하는 것
- 만약 추후에 pytest가 경로를 잘 못 찾을 경우 .pytest_cache를 한 번식 지워주면 테스트 코드 경로를 다시 탐색하게 되므로 문제해결 될 것임
- Note: 다른 경로에서 실행 시 다음과 같은 에러 발생 (그냥 참고!)
관리자@DESKTOP-THDM2MN MINGW64 ~/Desktop/projects/todos
$ pytest
====================================================================================================== test session starts =======================================================================================================
platform win32 -- Python 3.12.1, pytest-8.3.2, pluggy-1.5.0
rootdir: C:\Users\관리자\Desktop\projects\todos
plugins: anyio-4.2.0
collected 131 items / 22 errors
============================================================================================================= ERRORS =============================================================================================================
_________________________________________________________________________________ ERROR collecting Lib/site-packages/colorama/tests/ansi_test.py _________________________________________________________________________________
import file mismatch:
imported module 'colorama.tests.ansi_test' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\colorama\tests\ansi_test.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\colorama\tests\ansi_test.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
_____________________________________________________________________________ ERROR collecting Lib/site-packages/colorama/tests/ansitowin32_test.py ______________________________________________________________________________
import file mismatch:
imported module 'colorama.tests.ansitowin32_test' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\colorama\tests\ansitowin32_test.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\colorama\tests\ansitowin32_test.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
______________________________________________________________________________ ERROR collecting Lib/site-packages/colorama/tests/initialise_test.py ______________________________________________________________________________
import file mismatch:
imported module 'colorama.tests.initialise_test' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\colorama\tests\initialise_test.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\colorama\tests\initialise_test.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
________________________________________________________________________________ ERROR collecting Lib/site-packages/colorama/tests/isatty_test.py ________________________________________________________________________________
import file mismatch:
imported module 'colorama.tests.isatty_test' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\colorama\tests\isatty_test.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\colorama\tests\isatty_test.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
_______________________________________________________________________________ ERROR collecting Lib/site-packages/colorama/tests/winterm_test.py ________________________________________________________________________________
import file mismatch:
imported module 'colorama.tests.winterm_test' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\colorama\tests\winterm_test.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\colorama\tests\winterm_test.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
_____________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_contextvars.py ______________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_contextvars.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_________________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_cpp.py __________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_cpp.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_extension_interface.py __________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_extension_interface.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
__________________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_gc.py __________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_gc.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
______________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_generator.py _______________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_generator.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
___________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_generator_nested.py ___________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_generator_nested.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_______________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_greenlet.py _______________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_greenlet.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
____________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_greenlet_trash.py ____________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_greenlet_trash.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
________________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_leaks.py _________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_leaks.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_____________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_stack_saved.py ______________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_stack_saved.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
________________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_throw.py _________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_throw.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_______________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_tracing.py ________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_tracing.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_______________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_version.py ________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_version.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
_______________________________________________________________________________ ERROR collecting Lib/site-packages/greenlet/tests/test_weakref.py ________________________________________________________________________________
ImportError while importing test module 'C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\greenlet\tests\test_weakref.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
Lib\site-packages\greenlet\tests\__init__.py:27: in <module>
from . import leakcheck
Lib\site-packages\greenlet\tests\leakcheck.py:34: in <module>
import objgraph
E ModuleNotFoundError: No module named 'objgraph'
____________________________________________________________________________________________ ERROR collecting Lib/site-packages/numpy ____________________________________________________________________________________________
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1387: in _gcd_import
???
<frozen importlib._bootstrap>:1360: in _find_and_load
???
<frozen importlib._bootstrap>:1331: in _find_and_load_unlocked
???
<frozen importlib._bootstrap>:935: in _load_unlocked
???
..\..\..\AppData\Local\Programs\Python\Python312\Lib\site-packages\_pytest\assertion\rewrite.py:174: in exec_module
exec(co, module.__dict__)
Lib\site-packages\numpy\conftest.py:7: in <module>
import hypothesis
E ModuleNotFoundError: No module named 'hypothesis'
___________________________________________________________________________________________ ERROR collecting Lib/site-packages/pandas ____________________________________________________________________________________________
..\..\..\AppData\Local\Programs\Python\Python312\Lib\importlib\__init__.py:90: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1387: in _gcd_import
???
<frozen importlib._bootstrap>:1360: in _find_and_load
???
<frozen importlib._bootstrap>:1331: in _find_and_load_unlocked
???
<frozen importlib._bootstrap>:935: in _load_unlocked
???
..\..\..\AppData\Local\Programs\Python\Python312\Lib\site-packages\_pytest\assertion\rewrite.py:174: in exec_module
exec(co, module.__dict__)
Lib\site-packages\pandas\conftest.py:42: in <module>
import hypothesis
E ModuleNotFoundError: No module named 'hypothesis'
_______________________________________________________________________________ ERROR collecting Lib/site-packages/sniffio/_tests/test_sniffio.py ________________________________________________________________________________
import file mismatch:
imported module 'sniffio._tests.test_sniffio' has this __file__ attribute:
C:\Users\관리자\AppData\Local\Programs\Python\Python312\Lib\site-packages\sniffio\_tests\test_sniffio.py
which is not the same as the test file we want to collect:
C:\Users\관리자\Desktop\projects\todos\Lib\site-packages\sniffio\_tests\test_sniffio.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
==================================================================================================== short test summary info =====================================================================================================
ERROR Lib/site-packages/colorama/tests/ansi_test.py
ERROR Lib/site-packages/colorama/tests/ansitowin32_test.py
ERROR Lib/site-packages/colorama/tests/initialise_test.py
ERROR Lib/site-packages/colorama/tests/isatty_test.py
ERROR Lib/site-packages/colorama/tests/winterm_test.py
ERROR Lib/site-packages/greenlet/tests/test_contextvars.py
ERROR Lib/site-packages/greenlet/tests/test_cpp.py
ERROR Lib/site-packages/greenlet/tests/test_extension_interface.py
ERROR Lib/site-packages/greenlet/tests/test_gc.py
ERROR Lib/site-packages/greenlet/tests/test_generator.py
ERROR Lib/site-packages/greenlet/tests/test_generator_nested.py
ERROR Lib/site-packages/greenlet/tests/test_greenlet.py
ERROR Lib/site-packages/greenlet/tests/test_greenlet_trash.py
ERROR Lib/site-packages/greenlet/tests/test_leaks.py
ERROR Lib/site-packages/greenlet/tests/test_stack_saved.py
ERROR Lib/site-packages/greenlet/tests/test_throw.py
ERROR Lib/site-packages/greenlet/tests/test_tracing.py
ERROR Lib/site-packages/greenlet/tests/test_version.py
ERROR Lib/site-packages/greenlet/tests/test_weakref.py
ERROR Lib/site-packages/numpy - ModuleNotFoundError: No module named 'hypothesis'
ERROR Lib/site-packages/pandas - ModuleNotFoundError: No module named 'hypothesis'
ERROR Lib/site-packages/sniffio/_tests/test_sniffio.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 22 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================================================================================= 22 errors in 3.35s =======================================================================================================
PyCharm 사용 시
- PyCharm (i.e., 파이썬 IDE 통합 개발 환경 프로그램)을 사용할 경우 $ pytest 명령어를 실행 안 시켜도 검증해보기 가능
- 방법:
- test_main.py 안에 def test_health_check():의 line number 우측에서 초록색 화살표 클릭 > Run 'Python tests for tes...' 클릭
- → 테스트 코드가 동작되는 것 확인
이때까지의 코드들:
- /c/Users/관리자/Desktop/projects/todos/src/main.py (수정 - 삭제)
- /c/Users/관리자/Desktop/projects/todos/src/database/orm.py
- /c/Users/관리자/Desktop/projects/todos/src/database/connection.py
- /c/Users/관리자/Desktop/projects/todos/src/database/repository.py
- /c/Users/관리자/Desktop/projects/todos/src/schema/response.py
- /c/Users/관리자/Desktop/projects/todos/src/schema/request.py
- /c/Users/관리자/Desktop/projects/todos/src/tests/test_main.py (생성)
# /c/Users/관리자/Desktop/projects/todos/src/main.py 내용
from fastapi import FastAPI, Body, HTTPException, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session
from typing import List
from database.connection import get_db
from database.repository import get_todos, get_todo_by_todo_id, create_todo, update_todo, delete_todo
from database.orm import ToDo
from schema.response import ToDoSchema, ToDoListSchema
from schema.request import CreateToDoRequest
app = FastAPI()
# 첫 화면 API
@app.get("/")
def health_check_handler():
return {"ping": "pong"}
# 데이터베이스 역할하는 딕셔너리 생성 # 삭제
# todo_data = {
# 1: {
# "id": 1,
# "content": "실전! FastAPI 섹션 0 수강",
# "is_done": True,
# },
# 2: {
# "id": 2,
# "content": "실전! FastAPI 섹션 1 수강",
# "is_done": False,
# },
# 3: {
# "id": 3,
# "content": "실전! FastAPI 섹션 2 수강",
# "is_done": False,
# },
#}
# GET Method 사용하여 전체 조회 API - 딕셔너리 참조
# @app.get("/todos", status_code=200)
# def get_todos_handler(order: str | None = None):
# rt = list(todo_data.values())
# if order and order == "DESC":
# return rt[::-1]
# return rt
# GET Method 사용하여 전체 조회 API - DB 참조
@app.get("/todos", status_code=200)
def get_todos_handler(
order: str | None = None,
session: Session = Depends(get_db),
) -> ToDoListSchema:
todos: List[ToDo] = get_todos(session=session)
if order and order == "DESC":
# return todos[::-1]
return ToDoListSchema(
todos=[ToDoSchema.from_orm(todo) for todo in todos[::-1]]
)
# return todos
return ToDoListSchema(
todos=[ToDoSchema.from_orm(todo) for todo in todos]
)
# GET Method 사용하여 단일 조회 API
@app.get("/todos/{todo_id}", status_code=200)
def get_todo_handler(
todo_id: int,
session: Session=Depends(get_db),
) -> ToDoSchema:
todo:ToDo | None = get_todo_by_todo_id(session=session, todo_id = todo_id)
if todo:
return ToDoSchema.from_orm(todo)
raise HTTPException(status_code=404, detail="ToDo Not Found")
# POST Medthod 사용하여 todo 생성 API
@app.post("/todos", status_code=201)
def create_todo_handler(
request: CreateToDoRequest,
session: Session = Depends(get_db),
) -> ToDoSchema:
todo: ToDo = ToDo.create(request=request) # id=None
todo: ToDo = create_todo(session=session, todo=todo) # id=int
return ToDoSchema.from_orm(todo)
# PATCH Method 사용하여 is_done 값 수정 API
@app.patch("/todos/{todo_id}", status_code=200)
def update_todo_handler(
todo_id: int,
is_done: bool = Body(..., embed=True),
session: Session = Depends(get_db),
):
todo:ToDo | None = get_todo_by_todo_id(session=session, todo_id = todo_id)
if todo:
# update - is_done값이 True이면 todo.done() 실행, False이면 todo.undone() 실행
todo.done() if is_done else todo.undone()
todo: ToDo = update_todo(session=session, todo=todo)
return ToDoSchema.from_orm(todo)
raise HTTPException(status_code=404, detail="ToDo Not Found")
# DELETE Method 사용하여 todo 아이템 삭제 API
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo_handler(
todo_id: int,
session: Session = Depends(get_db),
):
todo:ToDo | None = get_todo_by_todo_id(session=session, todo_id = todo_id)
if not todo:
raise HTTPException(status_code=404, detail="ToDo Not Found")
delete_todo(session=session, todo_id=todo_id)
(main.py 변경)
# /c/Users/관리자/Desktop/projects/todos/src/database/orm.py 내용
from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import declarative_base
from schema.request import CreateToDoRequest
Base = declarative_base()
# ToDo 클래스 모델링 한 것
class ToDo(Base):
__tablename__ = 'todo'
id = Column(Integer, primary_key=True, index=True)
contents = Column(String(256), nullable=False)
is_done = Column(Boolean, nullable=False)
def __repr__(self):
return f"ToDo(id={self.id}, contents={self.contents}, is_done={self.is_done})"
@classmethod
def create(cls, request: CreateToDoRequest) -> "ToDo":
return cls(
# id값은 DB에 의해 자동으로 결정 되서 별도로 지정안해줌
contents=request.contents,
is_done=request.is_done,
)
def done(self) -> "ToDo":
# ToDo의 is_done 값을 True로 변경 후 ToDo 반환
self.is_done = True
return self
def undone(self) -> "ToDo":
# ToDo의 is_done 값을 False로 변경 후 ToDo 반환
self.is_done = False
return self
# /c/Users/관리자/Desktop/projects/todos/src/database/connection.py 내용
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos"
engine = create_engine(DATABASE_URL, echo=True)
SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
session = SessionFactory()
try:
yield session
finally:
session.close()
# /c/Users/관리자/Desktop/projects/todos/src/database/repository.py 내용
from sqlalchemy import select, delete
from sqlalchemy.orm import Session
from typing import List
from database.orm import ToDo
def get_todos(session: Session) -> List[ToDo]:
return list(session.scalars(select(ToDo)))
def get_todo_by_todo_id(session: Session, todo_id: int) -> ToDo | None:
return session.scalar(select(ToDo).where(ToDo.id == todo_id))
def create_todo(session: Session, todo: ToDo) -> ToDo:
session.add(instance=todo)
session.commit()
session.refresh(instance=todo)
return todo
def update_todo(session: Session, todo: ToDo) -> ToDo:
session.add(instance=todo)
session.commit()
session.refresh(instance=todo)
return todo
def delete_todo(session: Session, todo_id: ToDo) -> None:
session.execute(delete(ToDo).where(ToDo.id == todo_id))
session.commit()
# /c/Users/관리자/Desktop/projects/todos/src/schema/request.py 내용
from pydantic import BaseModel
class CreateToDoRequest(BaseModel):
contents: str
is_done: bool
# /c/Users/관리자/Desktop/projects/todos/src/schema/response.py 내용
from pydantic import BaseModel
from typing import List
class ToDoSchema(BaseModel):
id: int
contents: str
is_done: bool
class Config:
from_attributes = True
class ToDoListSchema(BaseModel):
todos: List[ToDoSchema]
# /c/Users/관리자/Desktop/projects/todos/src/tests/test_main.py 내용
from fastapi.testclient import TestClient
from main import app
client = TestClient(app=app)
def test_health_check():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"ping": "pong"}
(test_main.py 추가)
'Web 개발 > FAST API (인프런 강의 내용)' 카테고리의 다른 글
3 실습3 테스트 코드 - PyTest Mocking (0) | 2024.08.02 |
---|---|
3 실습2 테스트 코드 - GET 전체조회 API (0) | 2024.08.01 |
3 테스트 코드 PyTest (0) | 2024.06.01 |
2 실습11 ORM 적용 - DELETE API (0) | 2024.06.01 |
2 실습10 ORM 적용 - PATCH API (0) | 2024.06.01 |