Browse Source

๐ŸŒ Add Korean translation for `docs/ko/docs/tutorial/testing.md` (#12968)

pull/13055/head
timothy 4 months ago
committed by GitHub
parent
commit
230f2077b9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 243
      docs/ko/docs/tutorial/testing.md

243
docs/ko/docs/tutorial/testing.md

@ -0,0 +1,243 @@
# ํ…Œ์ŠคํŒ…
<a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a> ๋•๋ถ„์— **FastAPI** ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์ผ์€ ์‰ฝ๊ณ  ์ฆ๊ฑฐ์šด ์ผ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
Starlette๋Š” <a href="https://www.python-httpx.org\" class="external-link" target="_blank">HTTPX</a>๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ, ์ด๋Š” Requests๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์นœ์ˆ™ํ•˜๊ณ  ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค.
์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด FastAPI์—์„œ <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a>๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
## `TestClient` ์‚ฌ์šฉํ•˜๊ธฐ
/// info | ์ •๋ณด
`TestClient` ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ์šฐ์„  <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a> ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
[virtual environment](../virtual-environments.md){.internal-link target=_blank} ๋ฅผ ๋งŒ๋“ค๊ณ , ํ™œ์„ฑํ™” ์‹œํ‚จ ๋’ค์— ์„ค์น˜ํ•˜์„ธ์š”. ์˜ˆ์‹œ:
```console
$ pip install httpx
```
///
`TestClient` ๋ฅผ ์ž„ํฌํŠธํ•˜์„ธ์š”.
**FastAPI** ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ „๋‹ฌํ•˜์—ฌ `TestClient` ๋ฅผ ๋งŒ๋“œ์„ธ์š”.
์ด๋ฆ„์ด `test_` ๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ์„ธ์š”(`pytest` ์˜ ํ‘œ์ค€์ ์ธ ๊ด€๋ก€์ž…๋‹ˆ๋‹ค).
`httpx` ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ `TestClient` ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
ํ‘œ์ค€์ ์ธ ํŒŒ์ด์ฌ ๋ฌธ๋ฒ•์„ ์ด์šฉํ•˜์—ฌ ํ™•์ธ์ด ํ•„์š”ํ•œ ๊ณณ์— ๊ฐ„๋‹จํ•œ `assert` ๋ฌธ์žฅ์„ ์ž‘์„ฑํ•˜์„ธ์š”(์—ญ์‹œ ํ‘œ์ค€์ ์ธ `pytest` ๊ด€๋ก€์ž…๋‹ˆ๋‹ค).
{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
/// tip | ํŒ
ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜๋Š” `async def` ๊ฐ€ ์•„๋‹ˆ๋ผ `def` ๋กœ ์ž‘์„ฑ๋จ์— ์ฃผ์˜ํ•˜์„ธ์š”.
๊ทธ๋ฆฌ๊ณ  ํด๋ผ์ด์–ธํŠธ์— ๋Œ€ํ•œ ํ˜ธ์ถœ๋„ `await` ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ผ๋ฐ˜ ํ˜ธ์ถœ์ž…๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ํ•˜์—ฌ ๋ณต์žกํ•œ ๊ณผ์ • ์—†์ด `pytest` ๋ฅผ ์ง์ ‘์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
///
/// note | ๊ธฐ์ˆ  ์„ธ๋ถ€์‚ฌํ•ญ
`from starlette.testclient import TestClient` ์—ญ์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
**FastAPI** ๋Š” ๊ฐœ๋ฐœ์ž์˜ ํŽธ์˜๋ฅผ ์œ„ํ•ด `starlette.testclient` ๋ฅผ `fastapi.testclient` ๋กœ๋„ ์ œ๊ณตํ•  ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋‹จ์ง€ `Starlette` ์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๋Š”์ง€์˜ ์ฐจ์ด์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.
///
/// tip | ํŒ
FastAPI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ ์™ธ์—๋„ ํ…Œ์ŠคํŠธ์—์„œ `async` ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด (์˜ˆ: ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ•จ์ˆ˜), ์‹ฌํ™” ํŠœํ† ๋ฆฌ์–ผ์˜ [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.
///
## ํ…Œ์ŠคํŠธ ๋ถ„๋ฆฌํ•˜๊ธฐ
์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  **FastAPI** ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ์—ฌ๋Ÿฌ ํŒŒ์ผ์ด๋‚˜ ๋ชจ๋“ˆ ๋“ฑ์œผ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
### **FastAPI** app ํŒŒ์ผ
[Bigger Applications](bigger-applications.md){.internal-link target=_blank} ์— ๋ฌ˜์‚ฌ๋œ ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค.
```
.
โ”œโ”€โ”€ app
โ”‚ย ย  โ”œโ”€โ”€ __init__.py
โ”‚ย ย  โ””โ”€โ”€ main.py
```
`main.py` ํŒŒ์ผ ์•ˆ์— **FastAPI** app ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค:
{* ../../docs_src/app_testing/main.py *}
### ํ…Œ์ŠคํŠธ ํŒŒ์ผ
ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด `test_main.py` ๋ผ๋Š” ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์€ ๋™์ผํ•œ Python ํŒจํ‚ค์ง€(์ฆ‰, `__init__.py` ํŒŒ์ผ์ด ์žˆ๋Š” ๋™์ผํ•œ ๋””๋ ‰ํ„ฐ๋ฆฌ)์— ์œ„์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
``` hl_lines="5"
.
โ”œโ”€โ”€ app
โ”‚ย ย  โ”œโ”€โ”€ __init__.py
โ”‚ย ย  โ”œโ”€โ”€ main.py
โ”‚ย ย  โ””โ”€โ”€ test_main.py
```
ํŒŒ์ผ๋“ค์ด ๋™์ผํ•œ ํŒจํ‚ค์ง€์— ์œ„์น˜ํ•ด ์žˆ์œผ๋ฏ€๋กœ, ์ƒ๋Œ€ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ `main` ์—์„œ `app` ๊ฐ์ฒด๋ฅผ ์ž„ํฌํŠธ ํ•ด์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
{* ../../docs_src/app_testing/test_main.py hl[3] *}
...๊ทธ๋ฆฌ๊ณ  ์ด์ „์— ์ž‘์„ฑํ–ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
## ํ…Œ์ŠคํŠธ: ํ™•์žฅ๋œ ์˜ˆ์‹œ
์ด์ œ ์œ„์˜ ์˜ˆ์‹œ๋ฅผ ํ™•์žฅํ•˜๊ณ  ๋” ๋งŽ์€ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
### ํ™•์žฅ๋œ FastAPI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŒŒ์ผ
์ด์ „๊ณผ ๊ฐ™์€ ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
```
.
โ”œโ”€โ”€ app
โ”‚ย ย  โ”œโ”€โ”€ __init__.py
โ”‚ย ย  โ”œโ”€โ”€ main.py
โ”‚ย ย  โ””โ”€โ”€ test_main.py
```
์ด์ œ **FastAPI** ์•ฑ์ด ์žˆ๋Š” `main.py` ํŒŒ์ผ์— ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ **๊ฒฝ๋กœ ์ž‘์—…** ์ด ์ถ”๊ฐ€๋œ ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค.
๋‹จ์ผ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” `GET` ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” `POST` ์ž‘์—…์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๋‘ *๊ฒฝ๋กœ ์ž‘์—…* ๋ชจ๋‘ `X-Token` ํ—ค๋”๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
//// tab | Python 3.10+
```Python
{!> ../../docs_src/app_testing/app_b_an_py310/main.py!}
```
////
//// tab | Python 3.9+
```Python
{!> ../../docs_src/app_testing/app_b_an_py39/main.py!}
```
////
//// tab | Python 3.8+
```Python
{!> ../../docs_src/app_testing/app_b_an/main.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | ํŒ
๋  ์ˆ˜ ์žˆ์œผ๋ฉด `Annotated` ๋ฒ„์ „ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‚˜๋‹ค.
///
```Python
{!> ../../docs_src/app_testing/app_b_py310/main.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | ํŒ
๋  ์ˆ˜ ์žˆ์œผ๋ฉด `Annotated` ๋ฒ„์ „ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‚˜๋‹ค.
///
```Python
{!> ../../docs_src/app_testing/app_b/main.py!}
```
////
### ํ™•์žฅ๋œ ํ…Œ์ŠคํŠธ ํŒŒ์ผ
์ด์ œ๋Š” `test_main.py` ๋ฅผ ํ™•์žฅ๋œ ํ…Œ์ŠคํŠธ๋“ค๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
{* ../../docs_src/app_testing/app_b/test_main.py *}
ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์— ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋Š”๋ฐ ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด, `httpx`์—์„œ ํ•ด๋‹น ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒ€์ƒ‰(Google)ํ•˜๊ฑฐ๋‚˜, `requests`์—์„œ์˜ ๋ฐฉ๋ฒ•์„ ๊ฒ€์ƒ‰ํ•ด๋ณด์„ธ์š”. HTTPX๋Š” Requests์˜ ๋””์ž์ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ ํ›„, ํ…Œ์ŠคํŠธ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์ ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์˜ˆ์‹œ:
* *๊ฒฝ๋กœ* ํ˜น์€ *์ฟผ๋ฆฌ* ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด, URL ์ž์ฒด์— ์ถ”๊ฐ€ํ•œ๋‹ค.
* JSON ๋ณธ๋ฌธ์„ ์ „๋‹ฌํ•˜๋ ค๋ฉด, ํŒŒ์ด์ฌ ๊ฐ์ฒด (์˜ˆ๋ฅผ๋“ค๋ฉด `dict`) ๋ฅผ `json` ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•œ๋‹ค.
* JSON ๋Œ€์‹  *ํผ ๋ฐ์ดํ„ฐ* ๋ฅผ ๋ณด๋‚ด์•ผํ•œ๋‹ค๋ฉด, `data` ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋Œ€์‹  ์ „๋‹ฌํ•œ๋‹ค.
* *ํ—ค๋”* ๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด, `headers` ํŒŒ๋ผ๋ฏธํ„ฐ์— `dict` ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
* *์ฟ ํ‚ค* ๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด, `cookies` ํŒŒ๋ผ๋ฏธํ„ฐ์— `dict` ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.
๋ฐฑ์—”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณด๋‚ด๋Š”์ง€ ์ •๋ณด๋ฅผ ๋” ์–ป์œผ๋ ค๋ฉด (`httpx` ํ˜น์€ `TestClient` ๋ฅผ ์ด์šฉํ•ด์„œ) <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX documentation</a> ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
/// info | ์ •๋ณด
`TestClient` ๋Š” Pydantic ๋ชจ๋ธ์ด ์•„๋‹ˆ๋ผ JSON ์œผ๋กœ ๋ณ€ํ™˜๋  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.
๋งŒ์•ฝ ํ…Œ์ŠคํŠธ์ค‘ Pydantic ๋ชจ๋ธ์„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ์— ๋ณด๋‚ด๊ณ  ์‹ถ๋‹ค๋ฉด, [JSON ํ˜ธํ™˜ ๊ฐ€๋Šฅ ์ธ์ฝ”๋”](encoder.md){.internal-link target=_blank} ์— ์„ค๋ช…๋˜์–ด ์žˆ๋Š” `jsonable_encoder` ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
///
## ์‹คํ–‰ํ•˜๊ธฐ
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , `pytest` ๋ฅผ ์„ค์น˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
[virtual environment](../virtual-environments.md){.internal-link target=_blank} ๋ฅผ ๋งŒ๋“ค๊ณ , ํ™œ์„ฑํ™” ์‹œํ‚จ ๋’ค์— ์„ค์น˜ํ•˜์„ธ์š”. ์˜ˆ์‹œ:
<div class="termy">
```console
$ pip install pytest
---> 100%
```
</div>
`pytest` ํŒŒ์ผ๊ณผ ํ…Œ์ŠคํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ  ์‹คํ–‰ํ•œ ๋‹ค์Œ, ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค์Œ ๋ช…๋ น์–ด๋กœ ์‹คํ–‰ํ•˜์„ธ์š”.
<div class="termy">
```console
$ pytest
================ test session starts ================
platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /home/user/code/superawesome-cli/app
plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
collected 6 items
---> 100%
test_main.py <span style="color: green; white-space: pre;">...... [100%]</span>
<span style="color: green;">================= 1 passed in 0.03s =================</span>
```
</div>
Loadingโ€ฆ
Cancel
Save