orderflow_backtest/tests/test_visualizer_metrics.py

113 lines
4.3 KiB
Python
Raw Normal View History

"""Tests for Visualizer metrics integration."""
import sys
import sqlite3
import tempfile
from pathlib import Path
from unittest.mock import patch
sys.path.append(str(Path(__file__).resolve().parents[1]))
from visualizer import Visualizer
from models import Book, BookSnapshot, OrderbookLevel, Metric
from repositories.sqlite_metrics_repository import SQLiteMetricsRepository
def test_visualizer_loads_metrics():
"""Test that visualizer can load stored metrics from database."""
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp_file:
db_path = Path(tmp_file.name)
try:
# Create test database with metrics
metrics_repo = SQLiteMetricsRepository(db_path)
with metrics_repo.connect() as conn:
metrics_repo.create_metrics_table(conn)
# Insert test metrics
test_metrics = [
Metric(snapshot_id=1, timestamp=1000, obi=0.1, cvd=10.0, best_bid=50000.0, best_ask=50001.0),
Metric(snapshot_id=2, timestamp=1060, obi=0.2, cvd=15.0, best_bid=50002.0, best_ask=50003.0),
Metric(snapshot_id=3, timestamp=1120, obi=-0.1, cvd=12.0, best_bid=50004.0, best_ask=50005.0),
]
metrics_repo.insert_metrics_batch(conn, test_metrics)
conn.commit()
# Test visualizer
visualizer = Visualizer(window_seconds=60, max_bars=200)
visualizer.set_db_path(db_path)
# Load metrics directly to test the method
loaded_metrics = visualizer._load_stored_metrics(1000, 1120)
assert len(loaded_metrics) == 3
assert loaded_metrics[0].obi == 0.1
assert loaded_metrics[0].cvd == 10.0
assert loaded_metrics[1].obi == 0.2
assert loaded_metrics[2].obi == -0.1
finally:
db_path.unlink(missing_ok=True)
def test_visualizer_handles_no_database():
"""Test that visualizer handles gracefully when no database path is set."""
visualizer = Visualizer(window_seconds=60, max_bars=200)
# No database path set - should return empty list
metrics = visualizer._load_stored_metrics(1000, 2000)
assert metrics == []
def test_visualizer_handles_invalid_database():
"""Test that visualizer handles invalid database paths gracefully."""
visualizer = Visualizer(window_seconds=60, max_bars=200)
visualizer.set_db_path(Path("nonexistent.db"))
# Should handle error gracefully and return empty list
metrics = visualizer._load_stored_metrics(1000, 2000)
assert metrics == []
@patch('matplotlib.pyplot.subplots')
def test_visualizer_creates_four_subplots(mock_subplots):
"""Test that visualizer creates four subplots for OHLC, Volume, OBI, and CVD."""
# Mock the subplots creation
mock_fig = type('MockFig', (), {})()
mock_ax_ohlc = type('MockAx', (), {})()
mock_ax_volume = type('MockAx', (), {})()
mock_ax_obi = type('MockAx', (), {})()
mock_ax_cvd = type('MockAx', (), {})()
mock_subplots.return_value = (mock_fig, (mock_ax_ohlc, mock_ax_volume, mock_ax_obi, mock_ax_cvd))
# Create visualizer
visualizer = Visualizer(window_seconds=60, max_bars=200)
# Verify subplots were created correctly
mock_subplots.assert_called_once_with(4, 1, figsize=(12, 10), sharex=True)
assert visualizer.ax_ohlc == mock_ax_ohlc
assert visualizer.ax_volume == mock_ax_volume
assert visualizer.ax_obi == mock_ax_obi
assert visualizer.ax_cvd == mock_ax_cvd
def test_visualizer_update_from_book_with_empty_book():
"""Test that visualizer handles empty book gracefully."""
with patch('matplotlib.pyplot.subplots') as mock_subplots:
# Mock the subplots creation
mock_fig = type('MockFig', (), {'canvas': type('MockCanvas', (), {'draw_idle': lambda: None})()})()
mock_axes = [type('MockAx', (), {'clear': lambda: None})() for _ in range(4)]
mock_subplots.return_value = (mock_fig, tuple(mock_axes))
visualizer = Visualizer(window_seconds=60, max_bars=200)
# Test with empty book
book = Book()
# Should handle gracefully without errors
with patch('logging.warning') as mock_warning:
visualizer.update_from_book(book)
mock_warning.assert_called_once_with("Book has no snapshots to visualize")