148 lines
4.4 KiB
Python
148 lines
4.4 KiB
Python
|
|
"""
|
||
|
|
Portfolio API integration tests
|
||
|
|
"""
|
||
|
|
import pytest
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.integration
|
||
|
|
class TestPortfolioAPI:
|
||
|
|
"""Portfolio API endpoint tests"""
|
||
|
|
|
||
|
|
def test_create_portfolio_success(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_assets
|
||
|
|
):
|
||
|
|
"""Test successful portfolio creation"""
|
||
|
|
portfolio_data = {
|
||
|
|
"name": "테스트 포트폴리오",
|
||
|
|
"description": "API 테스트용",
|
||
|
|
"assets": [
|
||
|
|
{"ticker": "005930", "target_ratio": 50.0},
|
||
|
|
{"ticker": "000660", "target_ratio": 30.0},
|
||
|
|
{"ticker": "035420", "target_ratio": 20.0},
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
response = client.post("/api/v1/portfolios/", json=portfolio_data)
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
data = response.json()
|
||
|
|
assert "id" in data
|
||
|
|
assert data["name"] == portfolio_data["name"]
|
||
|
|
assert len(data["assets"]) == 3
|
||
|
|
|
||
|
|
def test_create_portfolio_invalid_ratio_sum(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_assets
|
||
|
|
):
|
||
|
|
"""Test portfolio creation with invalid ratio sum"""
|
||
|
|
portfolio_data = {
|
||
|
|
"name": "Invalid Ratio Portfolio",
|
||
|
|
"description": "목표 비율 합이 100이 아님",
|
||
|
|
"assets": [
|
||
|
|
{"ticker": "005930", "target_ratio": 50.0},
|
||
|
|
{"ticker": "000660", "target_ratio": 30.0},
|
||
|
|
# Sum = 80, not 100
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
response = client.post("/api/v1/portfolios/", json=portfolio_data)
|
||
|
|
|
||
|
|
# Should fail validation
|
||
|
|
assert response.status_code in [400, 422]
|
||
|
|
|
||
|
|
def test_create_portfolio_invalid_ticker(self, client: TestClient):
|
||
|
|
"""Test portfolio creation with non-existent ticker"""
|
||
|
|
portfolio_data = {
|
||
|
|
"name": "Invalid Ticker Portfolio",
|
||
|
|
"description": "존재하지 않는 종목코드",
|
||
|
|
"assets": [
|
||
|
|
{"ticker": "999999", "target_ratio": 100.0},
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
response = client.post("/api/v1/portfolios/", json=portfolio_data)
|
||
|
|
|
||
|
|
# Should fail validation
|
||
|
|
assert response.status_code in [400, 404]
|
||
|
|
|
||
|
|
def test_get_portfolio(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_portfolio
|
||
|
|
):
|
||
|
|
"""Test getting portfolio by ID"""
|
||
|
|
response = client.get(f"/api/v1/portfolios/{sample_portfolio.id}")
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
data = response.json()
|
||
|
|
assert data["id"] == str(sample_portfolio.id)
|
||
|
|
assert data["name"] == sample_portfolio.name
|
||
|
|
assert len(data["assets"]) == 3
|
||
|
|
|
||
|
|
def test_get_portfolio_not_found(self, client: TestClient):
|
||
|
|
"""Test getting non-existent portfolio"""
|
||
|
|
import uuid
|
||
|
|
fake_id = str(uuid.uuid4())
|
||
|
|
|
||
|
|
response = client.get(f"/api/v1/portfolios/{fake_id}")
|
||
|
|
|
||
|
|
assert response.status_code == 404
|
||
|
|
|
||
|
|
def test_list_portfolios(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_portfolio
|
||
|
|
):
|
||
|
|
"""Test listing portfolios"""
|
||
|
|
response = client.get("/api/v1/portfolios/?skip=0&limit=10")
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
data = response.json()
|
||
|
|
assert isinstance(data, list)
|
||
|
|
assert len(data) > 0
|
||
|
|
|
||
|
|
def test_update_portfolio(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_portfolio,
|
||
|
|
sample_assets
|
||
|
|
):
|
||
|
|
"""Test updating portfolio"""
|
||
|
|
update_data = {
|
||
|
|
"name": "Updated Portfolio Name",
|
||
|
|
"description": "Updated description",
|
||
|
|
"assets": [
|
||
|
|
{"ticker": "005930", "target_ratio": 60.0},
|
||
|
|
{"ticker": "000660", "target_ratio": 40.0},
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
response = client.put(
|
||
|
|
f"/api/v1/portfolios/{sample_portfolio.id}",
|
||
|
|
json=update_data
|
||
|
|
)
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
data = response.json()
|
||
|
|
assert data["name"] == update_data["name"]
|
||
|
|
assert len(data["assets"]) == 2
|
||
|
|
|
||
|
|
def test_delete_portfolio(
|
||
|
|
self,
|
||
|
|
client: TestClient,
|
||
|
|
sample_portfolio
|
||
|
|
):
|
||
|
|
"""Test deleting portfolio"""
|
||
|
|
response = client.delete(f"/api/v1/portfolios/{sample_portfolio.id}")
|
||
|
|
|
||
|
|
assert response.status_code == 200
|
||
|
|
|
||
|
|
# Verify deletion
|
||
|
|
get_response = client.get(f"/api/v1/portfolios/{sample_portfolio.id}")
|
||
|
|
assert get_response.status_code == 404
|