1. Aggiungere un aggregator per i dati recuperati dai provider. 2. Lavorare effettivamente all'issue Done: 1. creati test per i provider 2. creato market_providers_api_demo.py per mostrare i dati recuperati dalle api dei providers 3. aggiornato i provider 4. creato il provider binance sia pubblico che con chiave 5. creato error_handler.py per gestire decoratori e utilità: retry automatico, gestione timeout...
597 lines
23 KiB
Python
597 lines
23 KiB
Python
"""
|
|
Test suite completo per il sistema di mercato.
|
|
|
|
Questo modulo testa approfonditamente tutte le implementazioni di BaseWrapper
|
|
e verifica la conformità all'interfaccia definita in base.py.
|
|
"""
|
|
|
|
import os
|
|
import pytest
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
from typing import Type, List
|
|
|
|
# Import delle classi da testare
|
|
from app.markets.base import BaseWrapper, ProductInfo, Price
|
|
from app.markets.coinbase import CoinBaseWrapper
|
|
from app.markets.cryptocompare import CryptoCompareWrapper
|
|
from app.markets.binance import BinanceWrapper
|
|
from app.markets.binance_public import PublicBinanceAgent
|
|
from app.markets import MarketAPIs
|
|
|
|
|
|
class TestBaseWrapperInterface:
|
|
"""Test per verificare che tutte le implementazioni rispettino l'interfaccia BaseWrapper."""
|
|
|
|
def test_all_wrappers_extend_basewrapper(self):
|
|
"""Verifica che tutte le classi wrapper estendano BaseWrapper."""
|
|
wrapper_classes = [
|
|
CoinBaseWrapper,
|
|
CryptoCompareWrapper,
|
|
BinanceWrapper,
|
|
PublicBinanceAgent,
|
|
MarketAPIs
|
|
]
|
|
|
|
for wrapper_class in wrapper_classes:
|
|
assert issubclass(wrapper_class, BaseWrapper), f"{wrapper_class.__name__} deve estendere BaseWrapper"
|
|
|
|
def test_all_wrappers_implement_required_methods(self):
|
|
"""Verifica che tutte le classi implementino i metodi richiesti dall'interfaccia."""
|
|
wrapper_classes = [
|
|
CoinBaseWrapper,
|
|
CryptoCompareWrapper,
|
|
BinanceWrapper,
|
|
PublicBinanceAgent,
|
|
MarketAPIs
|
|
]
|
|
|
|
required_methods = ['get_product', 'get_products', 'get_all_products', 'get_historical_prices']
|
|
|
|
for wrapper_class in wrapper_classes:
|
|
for method in required_methods:
|
|
assert hasattr(wrapper_class, method), f"{wrapper_class.__name__} deve implementare {method}"
|
|
assert callable(getattr(wrapper_class, method)), f"{method} deve essere callable in {wrapper_class.__name__}"
|
|
|
|
|
|
class TestProductInfoModel:
|
|
"""Test per la classe ProductInfo e i suoi metodi di conversione."""
|
|
|
|
def test_productinfo_initialization(self):
|
|
"""Test inizializzazione di ProductInfo."""
|
|
product = ProductInfo()
|
|
assert product.id == ""
|
|
assert product.symbol == ""
|
|
assert product.price == 0.0
|
|
assert product.volume_24h == 0.0
|
|
assert product.status == ""
|
|
assert product.quote_currency == ""
|
|
|
|
def test_productinfo_with_data(self):
|
|
"""Test ProductInfo con dati specifici."""
|
|
product = ProductInfo(
|
|
id="BTC-USD",
|
|
symbol="BTC",
|
|
price=50000.0,
|
|
volume_24h=1000000.0,
|
|
status="TRADING",
|
|
quote_currency="USD"
|
|
)
|
|
assert product.id == "BTC-USD"
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
assert product.volume_24h == 1000000.0
|
|
assert product.status == "TRADING"
|
|
assert product.quote_currency == "USD"
|
|
|
|
def test_productinfo_from_cryptocompare(self):
|
|
"""Test conversione da dati CryptoCompare."""
|
|
mock_data = {
|
|
'FROMSYMBOL': 'BTC',
|
|
'TOSYMBOL': 'USD',
|
|
'PRICE': 50000.0,
|
|
'VOLUME24HOUR': 1000000.0
|
|
}
|
|
|
|
product = ProductInfo.from_cryptocompare(mock_data)
|
|
assert product.id == "BTC-USD"
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
assert product.volume_24h == 1000000.0
|
|
assert product.status == ""
|
|
|
|
def test_productinfo_from_binance(self):
|
|
"""Test conversione da dati Binance."""
|
|
ticker_data = {'symbol': 'BTCUSDT', 'price': '50000.0'}
|
|
ticker_24h_data = {'volume': '1000000.0'}
|
|
|
|
product = ProductInfo.from_binance(ticker_data, ticker_24h_data)
|
|
assert product.id == "BTCUSDT"
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
assert product.volume_24h == 1000000.0
|
|
assert product.status == "TRADING"
|
|
assert product.quote_currency == "USDT"
|
|
|
|
|
|
class TestPriceModel:
|
|
"""Test per la classe Price e i suoi metodi di conversione."""
|
|
|
|
def test_price_initialization(self):
|
|
"""Test inizializzazione di Price."""
|
|
price = Price()
|
|
assert price.high == 0.0
|
|
assert price.low == 0.0
|
|
assert price.open == 0.0
|
|
assert price.close == 0.0
|
|
assert price.volume == 0.0
|
|
assert price.time == ""
|
|
|
|
def test_price_with_data(self):
|
|
"""Test Price con dati specifici."""
|
|
price = Price(
|
|
high=51000.0,
|
|
low=49000.0,
|
|
open=50000.0,
|
|
close=50500.0,
|
|
volume=1000.0,
|
|
time="2024-01-01T00:00:00Z"
|
|
)
|
|
assert price.high == 51000.0
|
|
assert price.low == 49000.0
|
|
assert price.open == 50000.0
|
|
assert price.close == 50500.0
|
|
assert price.volume == 1000.0
|
|
assert price.time == "2024-01-01T00:00:00Z"
|
|
|
|
def test_price_from_cryptocompare(self):
|
|
"""Test conversione da dati CryptoCompare."""
|
|
mock_data = {
|
|
'high': 51000.0,
|
|
'low': 49000.0,
|
|
'open': 50000.0,
|
|
'close': 50500.0,
|
|
'volumeto': 1000.0,
|
|
'time': 1704067200
|
|
}
|
|
|
|
price = Price.from_cryptocompare(mock_data)
|
|
assert price.high == 51000.0
|
|
assert price.low == 49000.0
|
|
assert price.open == 50000.0
|
|
assert price.close == 50500.0
|
|
assert price.volume == 1000.0
|
|
assert price.time == "1704067200"
|
|
|
|
|
|
class TestCoinBaseWrapper:
|
|
"""Test specifici per CoinBaseWrapper."""
|
|
|
|
@pytest.mark.skipif(
|
|
not (os.getenv('COINBASE_API_KEY') and os.getenv('COINBASE_API_SECRET')),
|
|
reason="Credenziali Coinbase non configurate"
|
|
)
|
|
def test_coinbase_initialization_with_env_vars(self):
|
|
"""Test inizializzazione con variabili d'ambiente."""
|
|
wrapper = CoinBaseWrapper(currency="USD")
|
|
assert wrapper.currency == "USD"
|
|
assert wrapper.client is not None
|
|
|
|
@patch.dict(os.environ, {}, clear=True)
|
|
def test_coinbase_initialization_with_params(self):
|
|
"""Test inizializzazione con parametri espliciti quando non ci sono variabili d'ambiente."""
|
|
with pytest.raises(AssertionError, match="API key is required"):
|
|
CoinBaseWrapper(api_key=None, api_private_key=None)
|
|
|
|
@patch('app.markets.coinbase.RESTClient')
|
|
def test_coinbase_asset_formatting_behavior(self, mock_client):
|
|
"""Test comportamento di formattazione asset ID attraverso get_product."""
|
|
mock_response = Mock()
|
|
mock_response.product_id = "BTC-USD"
|
|
mock_response.base_currency_id = "BTC"
|
|
mock_response.price = "50000.0"
|
|
mock_response.volume_24h = "1000000.0"
|
|
mock_response.status = "TRADING"
|
|
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_product.return_value = mock_response
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
wrapper = CoinBaseWrapper(api_key="test", api_private_key="test")
|
|
|
|
# Test che entrambi i formati funzionino
|
|
wrapper.get_product("BTC")
|
|
wrapper.get_product("BTC-USD")
|
|
|
|
# Verifica che get_product sia stato chiamato con il formato corretto
|
|
assert mock_client_instance.get_product.call_count == 2
|
|
|
|
@patch('app.markets.coinbase.RESTClient')
|
|
def test_coinbase_get_product(self, mock_client):
|
|
"""Test get_product con mock."""
|
|
mock_response = Mock()
|
|
mock_response.product_id = "BTC-USD"
|
|
mock_response.base_currency_id = "BTC"
|
|
mock_response.price = "50000.0"
|
|
mock_response.volume_24h = "1000000.0"
|
|
mock_response.status = "TRADING"
|
|
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_product.return_value = mock_response
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
wrapper = CoinBaseWrapper(api_key="test", api_private_key="test")
|
|
product = wrapper.get_product("BTC")
|
|
|
|
assert isinstance(product, ProductInfo)
|
|
assert product.symbol == "BTC"
|
|
mock_client_instance.get_product.assert_called_once_with("BTC-USD")
|
|
|
|
|
|
class TestCryptoCompareWrapper:
|
|
"""Test specifici per CryptoCompareWrapper."""
|
|
|
|
@pytest.mark.skipif(
|
|
not os.getenv('CRYPTOCOMPARE_API_KEY'),
|
|
reason="CRYPTOCOMPARE_API_KEY non configurata"
|
|
)
|
|
def test_cryptocompare_initialization_with_env_var(self):
|
|
"""Test inizializzazione con variabile d'ambiente."""
|
|
wrapper = CryptoCompareWrapper(currency="USD")
|
|
assert wrapper.currency == "USD"
|
|
assert wrapper.api_key is not None
|
|
|
|
def test_cryptocompare_initialization_with_param(self):
|
|
"""Test inizializzazione con parametro esplicito."""
|
|
wrapper = CryptoCompareWrapper(api_key="test_key", currency="EUR")
|
|
assert wrapper.api_key == "test_key"
|
|
assert wrapper.currency == "EUR"
|
|
|
|
@patch('app.markets.cryptocompare.requests.get')
|
|
def test_cryptocompare_get_product(self, mock_get):
|
|
"""Test get_product con mock."""
|
|
mock_response = Mock()
|
|
mock_response.json.return_value = {
|
|
'RAW': {
|
|
'BTC': {
|
|
'USD': {
|
|
'FROMSYMBOL': 'BTC',
|
|
'TOSYMBOL': 'USD',
|
|
'PRICE': 50000.0,
|
|
'VOLUME24HOUR': 1000000.0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
mock_response.raise_for_status.return_value = None
|
|
mock_get.return_value = mock_response
|
|
|
|
wrapper = CryptoCompareWrapper(api_key="test_key")
|
|
product = wrapper.get_product("BTC")
|
|
|
|
assert isinstance(product, ProductInfo)
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
|
|
def test_cryptocompare_get_all_products_workaround(self):
|
|
"""Test che get_all_products funzioni con il workaround implementato."""
|
|
wrapper = CryptoCompareWrapper(api_key="test_key")
|
|
# Il metodo ora dovrebbe restituire una lista di ProductInfo invece di sollevare NotImplementedError
|
|
products = wrapper.get_all_products()
|
|
assert isinstance(products, list)
|
|
# Verifica che la lista non sia vuota (dovrebbe contenere almeno alcuni asset popolari)
|
|
assert len(products) > 0
|
|
# Verifica che ogni elemento sia un ProductInfo
|
|
for product in products:
|
|
assert isinstance(product, ProductInfo)
|
|
|
|
|
|
class TestBinanceWrapper:
|
|
"""Test specifici per BinanceWrapper."""
|
|
|
|
def test_binance_initialization_without_credentials(self):
|
|
"""Test che l'inizializzazione fallisca senza credenziali."""
|
|
# Assicuriamoci che le variabili d'ambiente siano vuote per questo test
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
with pytest.raises(AssertionError, match="API key is required"):
|
|
BinanceWrapper(api_key=None, api_secret="test")
|
|
|
|
with pytest.raises(AssertionError, match="API secret is required"):
|
|
BinanceWrapper(api_key="test", api_secret=None)
|
|
|
|
@patch('app.markets.binance.Client')
|
|
def test_binance_symbol_formatting_behavior(self, mock_client):
|
|
"""Test comportamento di formattazione simbolo attraverso get_product."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {
|
|
'symbol': 'BTCUSDT',
|
|
'price': '50000.0'
|
|
}
|
|
mock_client_instance.get_ticker.return_value = {
|
|
'volume': '1000000.0'
|
|
}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
wrapper = BinanceWrapper(api_key="test", api_secret="test")
|
|
|
|
# Test che entrambi i formati funzionino
|
|
wrapper.get_product("BTC")
|
|
wrapper.get_product("BTCUSDT")
|
|
|
|
# Verifica che i metodi siano stati chiamati
|
|
assert mock_client_instance.get_symbol_ticker.call_count == 2
|
|
|
|
@patch('app.markets.binance.Client')
|
|
def test_binance_get_product(self, mock_client):
|
|
"""Test get_product con mock."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {
|
|
'symbol': 'BTCUSDT',
|
|
'price': '50000.0'
|
|
}
|
|
mock_client_instance.get_ticker.return_value = {
|
|
'volume': '1000000.0'
|
|
}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
wrapper = BinanceWrapper(api_key="test", api_secret="test")
|
|
product = wrapper.get_product("BTC")
|
|
|
|
assert isinstance(product, ProductInfo)
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
|
|
|
|
class TestPublicBinanceAgent:
|
|
"""Test specifici per PublicBinanceAgent."""
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_initialization(self, mock_client):
|
|
"""Test inizializzazione senza credenziali."""
|
|
agent = PublicBinanceAgent()
|
|
assert agent.client is not None
|
|
mock_client.assert_called_once_with()
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_symbol_formatting_behavior(self, mock_client):
|
|
"""Test comportamento di formattazione simbolo attraverso get_product."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {
|
|
'symbol': 'BTCUSDT',
|
|
'price': '50000.0'
|
|
}
|
|
mock_client_instance.get_ticker.return_value = {
|
|
'volume': '1000000.0'
|
|
}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
agent = PublicBinanceAgent()
|
|
|
|
# Test che entrambi i formati funzionino
|
|
agent.get_product("BTC")
|
|
agent.get_product("BTCUSDT")
|
|
|
|
# Verifica che i metodi siano stati chiamati
|
|
assert mock_client_instance.get_symbol_ticker.call_count == 2
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_get_product(self, mock_client):
|
|
"""Test get_product con mock."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {
|
|
'symbol': 'BTCUSDT',
|
|
'price': '50000.0'
|
|
}
|
|
mock_client_instance.get_ticker.return_value = {
|
|
'volume': '1000000.0'
|
|
}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
agent = PublicBinanceAgent()
|
|
product = agent.get_product("BTC")
|
|
|
|
assert isinstance(product, ProductInfo)
|
|
assert product.symbol == "BTC"
|
|
assert product.price == 50000.0
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_get_all_products(self, mock_client):
|
|
"""Test get_all_products restituisce asset principali."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {
|
|
'symbol': 'BTCUSDT',
|
|
'price': '50000.0'
|
|
}
|
|
mock_client_instance.get_ticker.return_value = {
|
|
'volume': '1000000.0'
|
|
}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
agent = PublicBinanceAgent()
|
|
products = agent.get_all_products()
|
|
|
|
assert isinstance(products, list)
|
|
assert len(products) == 8 # Numero di asset principali definiti
|
|
for product in products:
|
|
assert isinstance(product, ProductInfo)
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_get_public_prices(self, mock_client):
|
|
"""Test metodo specifico get_public_prices."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.return_value = {'price': '50000.0'}
|
|
mock_client_instance.get_server_time.return_value = {'serverTime': 1704067200000}
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
agent = PublicBinanceAgent()
|
|
prices = agent.get_public_prices(["BTCUSDT"])
|
|
|
|
assert isinstance(prices, dict)
|
|
assert 'BTC_USD' in prices
|
|
assert prices['BTC_USD'] == 50000.0
|
|
assert 'source' in prices
|
|
assert prices['source'] == 'binance_public'
|
|
|
|
|
|
class TestMarketAPIs:
|
|
"""Test per la classe MarketAPIs che aggrega i wrapper."""
|
|
|
|
def test_market_apis_initialization_no_providers(self):
|
|
"""Test che l'inizializzazione fallisca senza provider disponibili."""
|
|
with patch.dict(os.environ, {}, clear=True):
|
|
with pytest.raises(AssertionError, match="No market API keys"):
|
|
MarketAPIs("USD")
|
|
|
|
@patch('app.markets.CoinBaseWrapper')
|
|
def test_market_apis_with_coinbase_only(self, mock_coinbase):
|
|
"""Test con solo Coinbase disponibile."""
|
|
mock_instance = Mock()
|
|
mock_coinbase.return_value = mock_instance
|
|
|
|
with patch('app.markets.CryptoCompareWrapper', side_effect=Exception("No API key")):
|
|
apis = MarketAPIs("USD")
|
|
assert len(apis.wrappers) == 1
|
|
assert apis.wrappers[0] == mock_instance
|
|
|
|
@patch('app.markets.CoinBaseWrapper')
|
|
@patch('app.markets.CryptoCompareWrapper')
|
|
def test_market_apis_delegation(self, mock_crypto, mock_coinbase):
|
|
"""Test che i metodi vengano delegati al primo wrapper disponibile."""
|
|
mock_coinbase_instance = Mock()
|
|
mock_crypto_instance = Mock()
|
|
mock_coinbase.return_value = mock_coinbase_instance
|
|
mock_crypto.return_value = mock_crypto_instance
|
|
|
|
apis = MarketAPIs("USD")
|
|
|
|
# Test delegazione get_product
|
|
apis.get_product("BTC")
|
|
mock_coinbase_instance.get_product.assert_called_once_with("BTC")
|
|
|
|
# Test delegazione get_products
|
|
apis.get_products(["BTC", "ETH"])
|
|
mock_coinbase_instance.get_products.assert_called_once_with(["BTC", "ETH"])
|
|
|
|
# Test delegazione get_all_products
|
|
apis.get_all_products()
|
|
mock_coinbase_instance.get_all_products.assert_called_once()
|
|
|
|
# Test delegazione get_historical_prices
|
|
apis.get_historical_prices("BTC")
|
|
mock_coinbase_instance.get_historical_prices.assert_called_once_with("BTC")
|
|
|
|
|
|
class TestErrorHandling:
|
|
"""Test per la gestione degli errori in tutti i wrapper."""
|
|
|
|
@patch('app.markets.binance_public.Client')
|
|
def test_public_binance_error_handling(self, mock_client):
|
|
"""Test gestione errori in PublicBinanceAgent."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.side_effect = Exception("API Error")
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
agent = PublicBinanceAgent()
|
|
product = agent.get_product("INVALID")
|
|
|
|
# Dovrebbe restituire un ProductInfo vuoto invece di sollevare eccezione
|
|
assert isinstance(product, ProductInfo)
|
|
assert product.id == "INVALID"
|
|
assert product.symbol == "INVALID"
|
|
|
|
@patch('app.markets.cryptocompare.requests.get')
|
|
def test_cryptocompare_network_error(self, mock_get):
|
|
"""Test gestione errori di rete in CryptoCompareWrapper."""
|
|
mock_get.side_effect = Exception("Network Error")
|
|
|
|
wrapper = CryptoCompareWrapper(api_key="test")
|
|
|
|
with pytest.raises(Exception):
|
|
wrapper.get_product("BTC")
|
|
|
|
@patch('app.markets.binance.Client')
|
|
def test_binance_api_error_in_get_products(self, mock_client):
|
|
"""Test gestione errori in BinanceWrapper.get_products."""
|
|
mock_client_instance = Mock()
|
|
mock_client_instance.get_symbol_ticker.side_effect = Exception("API Error")
|
|
mock_client.return_value = mock_client_instance
|
|
|
|
wrapper = BinanceWrapper(api_key="test", api_secret="test")
|
|
products = wrapper.get_products(["BTC", "ETH"])
|
|
|
|
# Dovrebbe restituire lista vuota invece di sollevare eccezione
|
|
assert isinstance(products, list)
|
|
assert len(products) == 0
|
|
|
|
|
|
class TestIntegrationScenarios:
|
|
"""Test di integrazione per scenari reali."""
|
|
|
|
def test_wrapper_method_signatures(self):
|
|
"""Verifica che tutti i wrapper abbiano le stesse signature dei metodi."""
|
|
wrapper_classes = [CoinBaseWrapper, CryptoCompareWrapper, BinanceWrapper, PublicBinanceAgent]
|
|
|
|
for wrapper_class in wrapper_classes:
|
|
# Verifica get_product
|
|
assert hasattr(wrapper_class, 'get_product')
|
|
|
|
# Verifica get_products
|
|
assert hasattr(wrapper_class, 'get_products')
|
|
|
|
# Verifica get_all_products
|
|
assert hasattr(wrapper_class, 'get_all_products')
|
|
|
|
# Verifica get_historical_prices
|
|
assert hasattr(wrapper_class, 'get_historical_prices')
|
|
|
|
def test_productinfo_consistency(self):
|
|
"""Test che tutti i metodi from_* di ProductInfo restituiscano oggetti consistenti."""
|
|
# Test from_cryptocompare
|
|
crypto_data = {
|
|
'FROMSYMBOL': 'BTC',
|
|
'TOSYMBOL': 'USD',
|
|
'PRICE': 50000.0,
|
|
'VOLUME24HOUR': 1000000.0
|
|
}
|
|
crypto_product = ProductInfo.from_cryptocompare(crypto_data)
|
|
|
|
# Test from_binance
|
|
binance_ticker = {'symbol': 'BTCUSDT', 'price': '50000.0'}
|
|
binance_24h = {'volume': '1000000.0'}
|
|
binance_product = ProductInfo.from_binance(binance_ticker, binance_24h)
|
|
|
|
# Verifica che entrambi abbiano gli stessi campi
|
|
assert hasattr(crypto_product, 'id')
|
|
assert hasattr(crypto_product, 'symbol')
|
|
assert hasattr(crypto_product, 'price')
|
|
assert hasattr(crypto_product, 'volume_24h')
|
|
|
|
assert hasattr(binance_product, 'id')
|
|
assert hasattr(binance_product, 'symbol')
|
|
assert hasattr(binance_product, 'price')
|
|
assert hasattr(binance_product, 'volume_24h')
|
|
|
|
def test_price_consistency(self):
|
|
"""Test che tutti i metodi from_* di Price restituiscano oggetti consistenti."""
|
|
# Test from_cryptocompare
|
|
crypto_data = {
|
|
'high': 51000.0,
|
|
'low': 49000.0,
|
|
'open': 50000.0,
|
|
'close': 50500.0,
|
|
'volumeto': 1000.0,
|
|
'time': 1704067200
|
|
}
|
|
crypto_price = Price.from_cryptocompare(crypto_data)
|
|
|
|
# Verifica che abbia tutti i campi richiesti
|
|
assert hasattr(crypto_price, 'high')
|
|
assert hasattr(crypto_price, 'low')
|
|
assert hasattr(crypto_price, 'open')
|
|
assert hasattr(crypto_price, 'close')
|
|
assert hasattr(crypto_price, 'volume')
|
|
assert hasattr(crypto_price, 'time')
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"])
|