84 lines
8.2 KiB
Plaintext
84 lines
8.2 KiB
Plaintext
============================= test session starts =============================
|
||
platform win32 -- Python 3.12.10, pytest-9.0.1, pluggy-1.6.0
|
||
rootdir: C:\tae\python\AutoCoinTrader
|
||
configfile: pytest.ini (WARNING: ignoring pytest config in pyproject.toml!)
|
||
collected 19 items
|
||
|
||
src\tests\test_concurrent_buy_orders.py F.... [ 26%]
|
||
src\tests\test_krw_budget_manager.py ............ [ 89%]
|
||
src\tests\test_recent_sells.py .. [100%]
|
||
|
||
================================== FAILURES ===================================
|
||
__________ TestConcurrentBuyOrders.test_concurrent_buy_no_overdraft ___________
|
||
|
||
self = <src.tests.test_concurrent_buy_orders.TestConcurrentBuyOrders object at 0x000001FEDB9DCDA0>
|
||
mock_price = <MagicMock name='get_current_price' id='2194123702000'>
|
||
mock_upbit_class = <MagicMock name='Upbit' id='2193668107552'>
|
||
mock_config = <Mock spec='RuntimeConfig' id='2193668107936'>
|
||
cleanup_budget = None
|
||
|
||
@patch('src.order.pyupbit.Upbit')
|
||
@patch('src.holdings.get_current_price')
|
||
def test_concurrent_buy_no_overdraft(self, mock_price, mock_upbit_class, mock_config, cleanup_budget):
|
||
"""동시 매수 시 잔고 초과 인출 방지 테스트"""
|
||
# Mock 설정
|
||
mock_upbit = MockUpbit(100000) # 10만원 초기 잔고
|
||
mock_upbit_class.return_value = mock_upbit
|
||
mock_price.return_value = 10000 # 코인당 1만원
|
||
|
||
results = []
|
||
|
||
def buy_worker(symbol: str, amount_krw: float):
|
||
"""매수 워커 스레드"""
|
||
result = place_buy_order_upbit(symbol, amount_krw, mock_config)
|
||
results.append((symbol, result))
|
||
|
||
# 3개 스레드가 동시에 50000원씩 매수 시도 (총 150000원 > 잔고 100000원)
|
||
threads = [
|
||
threading.Thread(target=buy_worker, args=(f"KRW-COIN{i}", 50000))
|
||
for i in range(3)
|
||
]
|
||
|
||
for t in threads:
|
||
t.start()
|
||
for t in threads:
|
||
t.join()
|
||
|
||
# 검증 1: 성공한 주문들의 총액이 초기 잔고를 초과하지 않음
|
||
successful_orders = [
|
||
r for symbol, r in results
|
||
if r.get("status") not in ("skipped_insufficient_budget", "skipped_insufficient_balance", "failed")
|
||
]
|
||
|
||
total_spent = sum(
|
||
r.get("amount_krw", 0) for _, r in results
|
||
if r.get("status") not in ("skipped_insufficient_budget", "skipped_insufficient_balance", "failed")
|
||
)
|
||
|
||
assert total_spent <= 100000, f"총 지출 {total_spent}원이 잔고 100000원을 초과"
|
||
|
||
# 검증 2: 최소 2개는 성공 (100000 / 50000 = 2)
|
||
> assert len(successful_orders) >= 2
|
||
E AssertionError: assert 1 >= 2
|
||
E + where 1 = len([{'amount_krw': 49975.0, 'market': 'KRW-COIN0', 'monitor': {'attempts': 0, 'filled_volume': 0.0, 'final_status': 'error', 'last_checked': 1765369729.6392872, ...}, 'price': 10049.999999999998, ...}])
|
||
|
||
src\tests\test_concurrent_buy_orders.py:133: AssertionError
|
||
------------------------------ Captured log call ------------------------------
|
||
WARNING macd_alarm:common.py:150 [KRW-COIN1] KRW 예산 할당 거부: 25원 < 최소 주문 5000원 (가용 25원)
|
||
WARNING macd_alarm:order.py:369 [매수 건너뜀] KRW-COIN1
|
||
사유: KRW 예산 부족
|
||
요청 금액: 50000 KRW
|
||
WARNING macd_alarm:common.py:150 [KRW-COIN2] KRW 예산 할당 거부: 25원 < 최소 주문 5000원 (가용 25원)
|
||
WARNING macd_alarm:order.py:369 [매수 건너뜀] KRW-COIN2
|
||
사유: KRW 예산 부족
|
||
요청 금액: 50000 KRW
|
||
ERROR macd_alarm:order.py:1190 주문 모니터링 중 오류 (1/5): 'MockUpbit' object has no attribute 'get_order'
|
||
ERROR macd_alarm:order.py:1190 주문 모니터링 중 오류 (2/5): 'MockUpbit' object has no attribute 'get_order'
|
||
ERROR macd_alarm:order.py:1190 주문 모니터링 중 오류 (3/5): 'MockUpbit' object has no attribute 'get_order'
|
||
ERROR macd_alarm:order.py:1190 주문 모니터링 중 오류 (4/5): 'MockUpbit' object has no attribute 'get_order'
|
||
ERROR macd_alarm:order.py:1190 주문 모니터링 중 오류 (5/5): 'MockUpbit' object has no attribute 'get_order'
|
||
ERROR macd_alarm:order.py:1193 주문 모니터링 중단: 연속 에러 5회 초과
|
||
=========================== short test summary info ===========================
|
||
FAILED src/tests/test_concurrent_buy_orders.py::TestConcurrentBuyOrders::test_concurrent_buy_no_overdraft
|
||
================== 1 failed, 18 passed in 169.65s (0:02:49) ===================
|
||
<EFBFBD> |