--- /dev/null
+# λΉλκΈ° ν
μ€νΈ μ½λ μμ±
+
+μ΄μ μ₯μμ `TestClient` λ₯Ό μ΄μ©ν΄ **FastAPI** μ΄ν리μΌμ΄μ
ν
μ€νΈλ₯Ό μμ±νλ λ²μ λ°°μ°μ
¨μν
λ°μ.
+μ§κΈκΉμ§λ `async` ν€μλ μ¬μ©μμ΄ λκΈ° ν¨μμ ν
μ€νΈ μ½λλ₯Ό μμ±νλ λ²λ§ μ΅νμ΅λλ€.
+
+νμ§λ§ λΉλκΈ° ν¨μλ₯Ό μ¬μ©νμ¬ ν
μ€νΈ μ½λλ₯Ό μμ±νλ κ²μ λ§€μ° μ μ©ν μ μμ΅λλ€.
+μλ₯Ό λ€λ©΄ λ°μ΄ν°λ² μ΄μ€μ λΉλκΈ°λ‘ μΏΌλ¦¬νλ κ²½μ°λ₯Ό μκ°ν΄λ΄
μλ€.
+FastAPI μ ν리μΌμ΄μ
μ μμ²μ 보λ΄κ³ , λΉλκΈ° λ°μ΄ν°λ² μ΄μ€ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λ°±μλκ° λ°μ΄ν°λ² μ΄μ€μ μ¬λ°λ₯΄κ² λ°μ΄ν°λ₯Ό κΈ°λ‘νλμ§ νμΈνκ³ μΆμ λκ° μμ κ²λλ€.
+
+μ΄λ° κ²½μ°μ ν
μ€νΈ μ½λλ₯Ό μ΄λ»κ² λΉλκΈ°λ‘ μμ±νλμ§ μμλ΄
μλ€.
+
+## pytest.mark.anyio
+
+μμμ μμ±ν ν
μ€νΈ ν¨μμμ λΉλκΈ° ν¨μλ₯Ό νΈμΆνκ³ μΆλ€λ©΄, ν
μ€νΈ μ½λλ λΉλκΈ° ν¨μμ¬μΌν©λλ€.
+AnyIOλ νΉμ ν
μ€νΈ ν¨μλ₯Ό λΉλκΈ° ν¨μλ‘ νΈμΆ ν μ μλ κΉλν νλ¬κ·ΈμΈμ μ 곡ν©λλ€.
+
+
+## HTTPX
+
+**FastAPI** μ ν리μΌμ΄μ
μ΄ `async def` λμ `def` ν€μλλ‘ μ μΈλ ν¨μλ₯Ό μ¬μ©νλλΌλ, λ΄λΆμ μΌλ‘λ μ¬μ ν `λΉλκΈ°` μ ν리μΌμ΄μ
μ
λλ€.
+
+`TestClient`λ pytest νμ€μ μ¬μ©νμ¬ λΉλκΈ° FastAPI μ ν리μΌμ΄μ
μ μΌλ°μ μΈ `def` ν
μ€νΈ ν¨μ λ΄μμ νΈμΆν μ μλλ‘ λ΄λΆμμ λ§μ μ λΆλ¦½λλ€. νμ§λ§ μ΄ λ§μ μ λΉλκΈ° ν¨μ λ΄λΆμμ μ¬μ©ν λλ λ μ΄μ μλνμ§ μμ΅λλ€. ν
μ€νΈλ₯Ό λΉλκΈ°λ‘ μ€ννλ©΄, λ μ΄μ ν
μ€νΈ ν¨μ λ΄λΆμμ `TestClient`λ₯Ό μ¬μ©ν μ μμ΅λλ€.
+
+`TestClient`λ <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>λ₯Ό κΈ°λ°μΌλ‘ νκ³ μμΌλ©°, λ€νν μ΄λ₯Ό μ§μ μ¬μ©νμ¬ APIλ₯Ό ν
μ€νΈν μ μμ΅λλ€.
+
+## μμ
+
+κ°λ¨ν μμλ₯Ό μν΄ [λ ν° μ΄ν리μΌμ΄μ
λ§λ€κΈ°](../ko/tutorial/bigger-applications.md){.internal-link target=_blank} μ [ν
μ€νΈ](../ko/tutorial/testing.md){.internal-link target=_blank}:μμ λ€λ£¬ νμΌ κ΅¬μ‘°μ λΉμ·ν ννλ₯Ό νμΈν΄λ΄
μλ€:
+
+```
+.
+βββ app
+βΒ Β βββ __init__.py
+βΒ Β βββ main.py
+βΒ Β βββ test_main.py
+```
+
+ `main.py`λ μλμ κ°μμΌ ν©λλ€:
+
+{* ../../docs_src/async_tests/main.py *}
+
+`test_main.py` νμΌμ `main.py`μ λν ν
μ€νΈκ° μμ ν
λ°, λ€μκ³Ό κ°μ μ μμ΅λλ€:
+
+{* ../../docs_src/async_tests/test_main.py *}
+
+## μ€ννκΈ°
+
+μλμ λͺ
λ Ήμ΄λ‘ ν
μ€νΈ μ½λλ₯Ό μ€νν©λλ€:
+
+<div class="termy">
+
+```console
+$ pytest
+
+---> 100%
+```
+
+</div>
+
+## μμΈν 보기
+
+`@pytest.mark.anyio` λ§μ»€λ pytestμκ² μ΄ ν
μ€νΈ ν¨μκ° λΉλκΈ°λ‘ νΈμΆλμ΄μΌ ν¨μ μλ €μ€λλ€:
+
+{* ../../docs_src/async_tests/test_main.py hl[7] *}
+
+/// tip | ν
+
+ν
μ€νΈ ν¨μκ° μ΄μ `TestClient`λ₯Ό μ¬μ©ν λμ²λΌ λ¨μν `def`κ° μλλΌ `async def`λ‘ μμ±λ μ μ μ£Όλͺ©ν΄μ£ΌμΈμ.
+
+///
+
+κ·Έ λ€μμ `AsyncClient` λ‘ μ±μ λ§λ€κ³ λΉλκΈ° μμ²μ `await` ν€μλλ‘ λ³΄λΌ μ μμ΅λλ€:
+
+{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
+
+μμ μ½λλ:
+
+```Python
+response = client.get('/')
+```
+
+`TestClient` μ μμ²μ 보λ΄λ κ²κ³Ό λμΌν©λλ€.
+
+/// tip | ν
+
+μλ‘μ΄ `AsyncClient`λ₯Ό μ¬μ©ν λ async/awaitλ₯Ό μ¬μ©νκ³ μλ€λ μ μ μ£Όλͺ©νμΈμ. μ΄ μμ²μ λΉλκΈ°μ μΌλ‘ μ²λ¦¬λ©λλ€.
+
+///
+
+/// warning | κ²½κ³
+
+λ§μ½μ μ΄ν리μΌμ΄μ
μ΄ Lifespan μ΄λ²€νΈμ μμ‘΄μ±μ κ°κ³ μλ€λ©΄ `AsyncClient` κ° μ΄λ¬ν μ΄λ²€νΈλ₯Ό μ€νμν€μ§ μμ΅λλ€.
+`AsyncClient` κ° ν
μ€νΈλ₯Ό μ€νμμΌ°λ€λ κ²μ νμΈνκΈ° μν΄
+`LifespanManager` from <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a>.νμΈν΄μ£ΌμΈμ.
+
+
+///
+
+## κ·Έ μΈμ λΉλκΈ° ν¨μ νΈμΆ
+
+ν
μ€νΈ ν¨μκ° μ΄μ λΉλκΈ° ν¨μμ΄λ―λ‘, FastAPI μ ν리μΌμ΄μ
μ μμ²μ 보λ΄λ κ² μΈμλ λ€λ₯Έ `async` ν¨μλ₯Ό νΈμΆνκ³ `await` ν€μλλ₯Ό μ¬μ© ν μ μμ΅λλ€.
+
+/// tip | ν
+
+ν
μ€νΈμ λΉλκΈ° ν¨μ νΈμΆμ ν΅ν©ν λ (μ: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDBμ MotorClient</a>λ₯Ό μ¬μ©ν λ) `RuntimeError: Task attached to a different loop` μ€λ₯κ° λ°μνλ€λ©΄, μ΄λ²€νΈ 루νκ° νμν κ°μ²΄λ λ°λμ λΉλκΈ° ν¨μ λ΄μμλ§ μΈμ€ν΄μ€νν΄μΌ νλ€λ μ μ μ£ΌμνμΈμ!
+μλ₯Ό λ€μ΄ `@app.on_event("startup")` μ½λ°± λ΄μμ μΈμ€ν΄μ€ννλ κ²μ΄ μ’μ΅λλ€.
+
+///