Files
crypto_trader/tests/unit/data/test_pricing_service.py

136 lines
4.6 KiB
Python

"""Unit tests for pricing service."""
import pytest
from unittest.mock import Mock, patch, MagicMock
from decimal import Decimal
from src.data.pricing_service import PricingService, get_pricing_service
from src.data.providers.base_provider import BasePricingProvider
class MockProvider(BasePricingProvider):
"""Mock provider for testing."""
@property
def name(self) -> str:
return "MockProvider"
@property
def supports_websocket(self) -> bool:
return False
def connect(self) -> bool:
self._connected = True
return True
def disconnect(self):
self._connected = False
def get_ticker(self, symbol: str):
return {
'symbol': symbol,
'bid': Decimal('50000'),
'ask': Decimal('50001'),
'last': Decimal('50000.5'),
'high': Decimal('51000'),
'low': Decimal('49000'),
'volume': Decimal('1000000'),
'timestamp': 1609459200000,
}
def get_ohlcv(self, symbol: str, timeframe: str = '1h', since=None, limit: int = 100):
return [[1609459200000, 50000, 51000, 49000, 50000, 1000]]
def subscribe_ticker(self, symbol: str, callback) -> bool:
if symbol not in self._subscribers:
self._subscribers[symbol] = []
self._subscribers[symbol].append(callback)
return True
@pytest.fixture
def mock_config():
"""Create a mock configuration."""
config = Mock()
config.get = Mock(side_effect=lambda key, default=None: {
"data_providers.primary": [
{"name": "mock", "enabled": True, "priority": 1}
],
"data_providers.fallback": {"enabled": True, "api_key": ""},
"data_providers.caching.ticker_ttl": 2,
"data_providers.caching.ohlcv_ttl": 60,
"data_providers.caching.max_cache_size": 1000,
}.get(key, default))
return config
class TestPricingService:
"""Tests for PricingService."""
@patch('src.data.pricing_service.get_config')
@patch('src.data.providers.ccxt_provider.CCXTProvider')
@patch('src.data.providers.coingecko_provider.CoinGeckoProvider')
def test_init(self, mock_coingecko, mock_ccxt, mock_get_config, mock_config):
"""Test service initialization."""
mock_get_config.return_value = mock_config
mock_ccxt_instance = MockProvider()
mock_ccxt.return_value = mock_ccxt_instance
mock_coingecko_instance = MockProvider()
mock_coingecko.return_value = mock_coingecko_instance
service = PricingService()
assert service.cache is not None
assert service.health_monitor is not None
@patch('src.data.pricing_service.get_config')
@patch('src.data.providers.ccxt_provider.CCXTProvider')
def test_get_ticker(self, mock_ccxt, mock_get_config, mock_config):
"""Test getting ticker data."""
mock_get_config.return_value = mock_config
mock_provider = MockProvider()
mock_ccxt.return_value = mock_provider
service = PricingService()
service._providers["MockProvider"] = mock_provider
service._active_provider = "MockProvider"
ticker = service.get_ticker("BTC/USD")
assert ticker['symbol'] == "BTC/USD"
assert isinstance(ticker['last'], Decimal)
@patch('src.data.pricing_service.get_config')
@patch('src.data.providers.ccxt_provider.CCXTProvider')
def test_get_ohlcv(self, mock_ccxt, mock_get_config, mock_config):
"""Test getting OHLCV data."""
mock_get_config.return_value = mock_config
mock_provider = MockProvider()
mock_ccxt.return_value = mock_provider
service = PricingService()
service._providers["MockProvider"] = mock_provider
service._active_provider = "MockProvider"
ohlcv = service.get_ohlcv("BTC/USD", "1h", limit=10)
assert len(ohlcv) > 0
assert len(ohlcv[0]) == 6
@patch('src.data.pricing_service.get_config')
@patch('src.data.providers.ccxt_provider.CCXTProvider')
def test_subscribe_ticker(self, mock_ccxt, mock_get_config, mock_config):
"""Test subscribing to ticker updates."""
mock_get_config.return_value = mock_config
mock_provider = MockProvider()
mock_ccxt.return_value = mock_provider
service = PricingService()
service._providers["MockProvider"] = mock_provider
service._active_provider = "MockProvider"
callback = Mock()
result = service.subscribe_ticker("BTC/USD", callback)
assert result is True