- Created tests/fixtures/ with FixtureLoader class (14 loader methods) - Added stock_data fixtures: US, CN (with Chinese columns), standardized OHLCV - Added metadata fixtures: 5 analysis examples with datetime parsing - Added report_sections fixtures: 7 complete analyst report sections - Added api_responses fixtures: OpenAI embeddings and error responses - Added configurations fixtures: vendor and LLM provider configs - Created comprehensive README.md (595 lines) documenting fixture usage - Updated docs/testing/writing-tests.md with fixture examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| api_responses | ||
| configurations | ||
| metadata | ||
| report_sections | ||
| stock_data | ||
| README.md | ||
| __init__.py | ||
README.md
Test Fixtures
Centralized test fixtures for TradingAgents test suite. This directory provides mock data for stock market OHLCV data, analysis metadata, report sections, API responses, and configurations.
Directory Structure
tests/fixtures/
├── __init__.py # FixtureLoader class and convenience functions
├── README.md # This file
├── stock_data/ # Stock market OHLCV data
│ ├── us_market_ohlcv.json
│ ├── cn_market_ohlcv.json
│ └── standardized_ohlcv.json
├── metadata/ # Analysis metadata
│ └── analysis_metadata.json
├── report_sections/ # Complete report sections
│ └── complete_reports.json
├── api_responses/ # Mock API responses
│ └── openai_embeddings.json
└── configurations/ # Configuration examples
└── default_config.json
Quick Start
Basic Usage
from tests.fixtures import FixtureLoader
# Load US stock data
df = FixtureLoader.load_us_stock_data()
print(df.head())
# Load Chinese stock data (with Chinese column names)
cn_df = FixtureLoader.load_cn_stock_data()
# Load Chinese stock data (standardized to English)
cn_df_std = FixtureLoader.load_cn_stock_data(standardize=True)
# Load analysis metadata
metadata = FixtureLoader.load_analysis_metadata("complete_analysis")
# Load report sections
sections = FixtureLoader.load_complete_report_sections()
# Load API responses
embedding = FixtureLoader.load_embedding_response()
# Load configuration
config = FixtureLoader.load_default_config("complete_config")
Convenience Functions
# Import convenience functions directly
from tests.fixtures import (
load_us_stock_data,
load_cn_stock_data,
load_analysis_metadata,
load_complete_report_sections,
load_embedding_response,
load_default_config,
)
# Use them directly
df = load_us_stock_data()
metadata = load_analysis_metadata()
Fixture Details
Stock Data Fixtures
US Market Data (stock_data/us_market_ohlcv.json)
OHLCV data for AAPL (Apple Inc.) from 2024-11-01 to 2024-11-15.
Columns: Date, Open, High, Low, Close, Volume
Usage:
# Load main data
df = FixtureLoader.load_us_stock_data()
# Load edge cases
empty = FixtureLoader.load_us_stock_data(edge_case="empty_data")
single = FixtureLoader.load_us_stock_data(edge_case="single_row")
missing_vol = FixtureLoader.load_us_stock_data(edge_case="missing_volume")
out_of_order = FixtureLoader.load_us_stock_data(edge_case="out_of_order_dates")
Edge Cases:
empty_data: Empty DataFrame for testing empty data handlingsingle_row: Single row of datamissing_volume: Data with Volume column missingout_of_order_dates: Dates not in chronological order
Chinese Market Data (stock_data/cn_market_ohlcv.json)
OHLCV data for 600519.SH (贵州茅台 - Kweichow Moutai) from 2024-11-01 to 2024-11-15.
Columns (Chinese): 日期, 开盘, 最高, 最低, 收盘, 成交量
Column Mapping:
- 日期 → Date
- 开盘 → Open
- 最高 → High
- 最低 → Low
- 收盘 → Close
- 成交量 → Volume
Usage:
# Load with Chinese column names
cn_df = FixtureLoader.load_cn_stock_data()
print(cn_df.columns) # ['开盘', '最高', '最低', '收盘', '成交量']
# Load with standardized English column names
cn_df_std = FixtureLoader.load_cn_stock_data(standardize=True)
print(cn_df_std.columns) # ['Open', 'High', 'Low', 'Close', 'Volume']
# Load edge cases
empty = FixtureLoader.load_cn_stock_data(edge_case="empty_data")
mixed = FixtureLoader.load_cn_stock_data(edge_case="mixed_columns")
Edge Cases:
empty_data: Empty DataFramemixed_columns: Mix of Chinese and English column names
Standardized Data (stock_data/standardized_ohlcv.json)
Standardized OHLCV data for TSLA from 2024-11-01 to 2024-11-14. Represents data after processing and standardization, ready for technical analysis.
Usage:
df = FixtureLoader.load_standardized_stock_data()
Metadata Fixtures
Analysis Metadata (metadata/analysis_metadata.json)
Metadata for stock analysis reports including ticker, date range, analysts, data vendors, LLM providers, and execution details.
Available Examples:
complete_analysis: Full analysis with all sections completedpartial_analysis: Partial analysis with some missing sectionsmulti_ticker_batch: Batch analysis for multiple tickerschinese_market_analysis: Chinese market analysis with localizationerror_scenario: Failed analysis with error details
Usage:
# Complete analysis
metadata = FixtureLoader.load_analysis_metadata("complete_analysis")
print(metadata["ticker"]) # 'AAPL'
print(metadata["status"]) # 'complete'
# Partial analysis
partial = FixtureLoader.load_analysis_metadata("partial_analysis")
print(partial["missing_sections"]) # ['news_report', 'fundamentals_report', ...]
# Error scenario
error = FixtureLoader.load_analysis_metadata("error_scenario")
print(error["error_type"]) # 'DataNotFoundError'
Report Section Fixtures
Complete Reports (report_sections/complete_reports.json)
Full report sections for comprehensive analysis. Includes all analyst reports from market analysis to final trade decision.
Available Sections:
market_report: Technical analysis and market overviewsentiment_report: Social sentiment analysisnews_report: News analysis and impact assessmentfundamentals_report: Fundamental analysis with financialsinvestment_plan: Long-term investment strategytrader_investment_plan: Short-term trading planfinal_trade_decision: Executive decision and order details
Usage:
# Load all sections
sections = FixtureLoader.load_complete_report_sections()
print(sections["market_report"]["content"][:50])
# Load specific section
market = FixtureLoader.load_report_section("market_report")
print(market["analyst"]) # 'market'
print(market["generated_at"]) # datetime object
# Load partial sections (some None)
partial = FixtureLoader.load_partial_report_sections()
print(partial["market_report"]) # Has content
print(partial["sentiment_report"]) # None
API Response Fixtures
OpenAI Embeddings (api_responses/openai_embeddings.json)
Mock OpenAI API responses for embedding requests. Useful for testing without making actual API calls.
Available Examples:
single_text_embedding: Single embedding responsebatch_text_embeddings: Multiple embeddings in one responsefinancial_situation_embedding: Embedding for financial situation textlarge_embedding_1536: Full-size 1536-dimension embedding (truncated in fixture)
Available Errors:
rate_limit_error: Rate limit exceeded errorinvalid_api_key: Invalid API key errormodel_not_found: Model not found error
Usage:
# Load embedding response
response = FixtureLoader.load_embedding_response("single_text_embedding")
embedding_vector = response["data"][0]["embedding"]
print(len(embedding_vector)) # 20 (truncated for testing)
# Load batch embeddings
batch = FixtureLoader.load_embedding_response("batch_text_embeddings")
print(len(batch["data"])) # 3
# Load error response
error = FixtureLoader.load_embedding_error("rate_limit_error")
print(error["error"]["type"]) # 'rate_limit_error'
Configuration Fixtures
Default Configurations (configurations/default_config.json)
Configuration examples for different scenarios and vendor setups.
Available Examples:
complete_config: Full configuration with all optionsminimal_config: Minimal required configurationchinese_market_config: Chinese market-specific configurationhigh_frequency_config: High-frequency trading configurationtesting_config: Testing/development configuration
Vendor-Specific Configs:
alpaca: Alpaca API configurationalpha_vantage: Alpha Vantage API configurationakshare: AKShare (Chinese market) configurationyfinance: Yahoo Finance configuration
LLM Provider Configs:
openrouter: OpenRouter configurationopenai: OpenAI configurationanthropic: Anthropic configurationollama: Ollama (local) configuration
Usage:
# Load complete config
config = FixtureLoader.load_default_config("complete_config")
print(config["data_vendor"]) # 'alpaca'
# Load minimal config
minimal = FixtureLoader.load_default_config("minimal_config")
# Load vendor-specific config
alpaca_config = FixtureLoader.load_vendor_config("alpaca")
print(alpaca_config["paper_trading"]) # True
# Load LLM provider config
openrouter = FixtureLoader.load_llm_provider_config("openrouter")
print(openrouter["backend_url"]) # 'https://openrouter.ai/api/v1'
Advanced Usage
Loading Custom Fixtures
# Load arbitrary JSON fixture
custom_data = FixtureLoader.load_json_fixture("path/to/custom.json")
# Load as DataFrame
df = FixtureLoader.load_dataframe_fixture(
"path/to/data.json",
data_key="data",
date_column="Date",
set_index=True
)
Datetime Parsing
All datetime strings in JSON fixtures are automatically parsed to Python datetime objects. Supports ISO 8601 format:
{
"generated_at": "2024-12-26T14:30:00",
"analysis_date": "2024-12-26",
"created_at": "2024-12-26T10:30:00+08:00"
}
After loading:
metadata = FixtureLoader.load_analysis_metadata()
print(type(metadata["generated_at"])) # <class 'datetime.datetime'>
Working with DataFrames
# Load stock data
df = FixtureLoader.load_us_stock_data()
# Date is already the index
print(df.index.name) # 'Date'
print(df.index.dtype) # datetime64[ns]
# Columns are OHLCV
print(df.columns.tolist()) # ['Open', 'High', 'Low', 'Close', 'Volume']
# Ready for technical analysis
df['SMA_20'] = df['Close'].rolling(window=20).mean()
Testing Edge Cases
import pytest
def test_handles_empty_data():
"""Test that function handles empty DataFrame gracefully."""
empty_df = FixtureLoader.load_us_stock_data(edge_case="empty_data")
assert empty_df.empty
result = process_stock_data(empty_df)
assert result is None or result.empty
def test_handles_missing_volume():
"""Test that function handles missing Volume column."""
df = FixtureLoader.load_us_stock_data(edge_case="missing_volume")
assert "Volume" not in df.columns
# Should not raise error
result = calculate_indicators(df)
assert result is not None
Writing Tests with Fixtures
Basic Test Example
import pytest
from tests.fixtures import FixtureLoader
def test_stock_data_processing():
"""Test stock data processing with fixture."""
# Arrange
df = FixtureLoader.load_us_stock_data()
# Act
result = process_stock_data(df)
# Assert
assert result is not None
assert len(result) == len(df)
assert result.index.equals(df.index)
Pytest Fixture Integration
import pytest
from tests.fixtures import FixtureLoader
@pytest.fixture
def us_stock_data():
"""Provide US stock data for tests."""
return FixtureLoader.load_us_stock_data()
@pytest.fixture
def analysis_metadata():
"""Provide analysis metadata for tests."""
return FixtureLoader.load_analysis_metadata()
def test_with_fixtures(us_stock_data, analysis_metadata):
"""Test using pytest fixtures."""
result = analyze_stock(
data=us_stock_data,
ticker=analysis_metadata["ticker"]
)
assert result["ticker"] == "AAPL"
Parameterized Tests
import pytest
from tests.fixtures import FixtureLoader
@pytest.mark.parametrize("edge_case", [
"empty_data",
"single_row",
"missing_volume",
"out_of_order_dates"
])
def test_edge_cases(edge_case):
"""Test handling of various edge cases."""
df = FixtureLoader.load_us_stock_data(edge_case=edge_case)
# Should not raise exception
result = process_stock_data(df)
# Should handle gracefully
assert result is not None or df.empty
Mocking API Responses
from unittest.mock import patch, MagicMock
from tests.fixtures import FixtureLoader
def test_embedding_api_call():
"""Test embedding API call with mock response."""
# Load mock response
mock_response = FixtureLoader.load_embedding_response()
# Mock the API client
with patch('openai.OpenAI') as mock_client:
mock_client.return_value.embeddings.create.return_value = MagicMock(
**mock_response
)
# Test function that uses embeddings
result = get_text_embedding("test text")
# Verify
assert result is not None
assert len(result) > 0
Best Practices
1. Use Fixtures Over Hardcoded Data
Bad:
def test_stock_processing():
df = pd.DataFrame({
'Date': ['2024-11-01', '2024-11-02'],
'Close': [100, 101]
})
# ...
Good:
def test_stock_processing():
df = FixtureLoader.load_us_stock_data()
# ...
2. Test Edge Cases
Always test edge cases using the provided edge case fixtures:
def test_empty_data_handling():
df = FixtureLoader.load_us_stock_data(edge_case="empty_data")
result = process_data(df)
assert result is not None # Should not crash
def test_missing_column_handling():
df = FixtureLoader.load_us_stock_data(edge_case="missing_volume")
result = calculate_volume_indicators(df)
assert result is None or result.empty # Graceful degradation
3. Use Appropriate Fixture Type
- Unit tests: Use small, focused fixtures (single row, minimal data)
- Integration tests: Use complete fixtures (full data range)
- Performance tests: Use edge cases (empty data, large datasets)
4. Document Custom Fixtures
If you add custom fixtures:
- Add JSON file to appropriate subdirectory
- Add loader method to
FixtureLoaderclass - Add documentation to this README
- Add usage examples
5. Keep Fixtures Realistic
Fixtures should represent realistic data:
- Use actual stock symbols (AAPL, TSLA, 600519.SH)
- Use realistic price ranges and volumes
- Include realistic metadata and timestamps
- Mirror actual API response structures
Maintenance
Adding New Fixtures
- Create JSON file in appropriate subdirectory
- Follow naming convention:
{category}_{description}.json - Include description field in JSON
- Add loader method to
FixtureLoaderclass - Update this README with usage examples
- Add tests for the new fixture loader
Modifying Existing Fixtures
- Maintain backward compatibility when possible
- Update documentation if structure changes
- Update affected tests
- Consider adding new example instead of modifying existing
Versioning
Fixtures are versioned with the project. Breaking changes to fixture structure should:
- Increment project version
- Document migration path in CHANGELOG
- Provide legacy fixtures for compatibility (if needed)
Troubleshooting
FileNotFoundError
# Error: FileNotFoundError: Fixture not found
# Solution: Check path is relative to fixtures directory
df = FixtureLoader.load_json_fixture("stock_data/us_market_ohlcv.json") # Correct
KeyError: 'data'
# Error: KeyError: Key 'data' not found in fixture
# Solution: Specify correct data_key
df = FixtureLoader.load_dataframe_fixture(
"path/to/file.json",
data_key="examples" # Not "data"
)
Datetime Not Parsed
# Dates are strings instead of datetime objects
# Solution: Ensure date format is ISO 8601
# Good: "2024-11-01T00:00:00" or "2024-11-01"
# Bad: "11/01/2024" or "Nov 1, 2024"
Empty DataFrame
# Getting empty DataFrame unexpectedly
# Check if loading edge case by mistake
df = FixtureLoader.load_us_stock_data() # Main data
df = FixtureLoader.load_us_stock_data(edge_case=None) # Explicit
Contributing
When contributing new fixtures:
- Follow existing JSON structure patterns
- Use UTF-8 encoding (especially for Chinese characters)
- Format dates as ISO 8601 strings
- Include both main data and edge cases
- Add comprehensive docstrings to loader methods
- Update this README with usage examples
- Add unit tests for new loader methods
License
These fixtures are part of the TradingAgents project and are provided for testing purposes only. Stock data is synthetic and should not be used for actual trading decisions.
See Also
- Testing Guide - Testing best practices
- Pytest Documentation - Pytest framework
- Pandas Documentation - DataFrame operations