Skip to main content
Glama

MCP Stock Details Server

by whdghk1907
test_valuation_metrics.pyβ€’11.3 kB
""" Unit tests for valuation metrics functionality TDD Red Phase: Write failing tests for valuation analysis """ import pytest import asyncio from unittest.mock import Mock, AsyncMock, patch from datetime import datetime, date from typing import Any, Dict, List, Optional # Test imports - initially will fail (TDD Red phase) from src.server import MCPStockDetailsServer from src.tools.valuation_tools import ValuationAnalyzer from src.exceptions import MCPStockDetailsError, InsufficientDataError class TestValuationMetrics: """Test cases for valuation metrics functionality""" @pytest.fixture def server_with_valuation(self): """Create server instance with valuation analyzer""" server = MCPStockDetailsServer() # This will fail initially - Red phase server.valuation_analyzer = ValuationAnalyzer() return server @pytest.fixture def sample_market_data(self): """Sample market data for valuation calculations""" return { "005930": { # Samsung Electronics "current_price": 73000, "market_cap": 435_000_000_000_000, # 435 trillion KRW "shares_outstanding": 5_969_782_550, "52_week_high": 80000, "52_week_low": 65000, "trading_volume": 15_000_000, "financial_data": { "2023": { "revenue": 258_774_000_000_000, "net_profit": 15_349_000_000_000, "book_value": 319_684_000_000_000, "ebitda": 28_500_000_000_000, "enterprise_value": 420_000_000_000_000, "free_cash_flow": 29_163_000_000_000, "total_debt": 85_000_000_000_000, "cash_and_equivalents": 25_000_000_000_000 } } } } @pytest.mark.asyncio async def test_get_valuation_metrics_tool_registration(self, server_with_valuation): """Test that get_valuation_metrics tool is properly registered""" tools = await server_with_valuation.list_tools() tool_names = [tool.name for tool in tools] assert "get_valuation_metrics" in tool_names # Check tool description and parameters valuation_tool = next(tool for tool in tools if tool.name == "get_valuation_metrics") assert "valuation" in valuation_tool.description.lower() assert "company_code" in valuation_tool.inputSchema["properties"] @pytest.mark.asyncio async def test_basic_price_multiples_calculation(self, server_with_valuation, sample_market_data): """Test basic price multiples (PER, PBR, PSR)""" company_code = "005930" with patch.object(server_with_valuation.valuation_analyzer, 'get_market_data') as mock_market: mock_market.return_value = sample_market_data[company_code] result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "include_multiples": True }) assert result is not None assert len(result) > 0 content = result[0].text # Should include price multiples assert "VALUATION MULTIPLES" in content assert "PER" in content or "P/E Ratio" in content assert "PBR" in content or "P/B Ratio" in content assert "PSR" in content or "P/S Ratio" in content # Should show calculated values assert "73,000" in content or "73000" in content # Current price @pytest.mark.asyncio async def test_enterprise_value_multiples(self, server_with_valuation, sample_market_data): """Test enterprise value multiples (EV/EBITDA, EV/Sales)""" company_code = "005930" with patch.object(server_with_valuation.valuation_analyzer, 'get_market_data') as mock_market: mock_market.return_value = sample_market_data[company_code] result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "include_ev_multiples": True }) assert result is not None content = result[0].text # Should include EV multiples assert "ENTERPRISE VALUE MULTIPLES" in content assert "EV/EBITDA" in content assert "EV/Sales" in content or "EV/Revenue" in content assert "Enterprise Value" in content @pytest.mark.asyncio async def test_historical_valuation_bands(self, server_with_valuation): """Test historical valuation bands analysis""" company_code = "005930" result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "include_historical_bands": True, "band_period": "3Y" # 3 years }) assert result is not None content = result[0].text # Should include historical analysis assert "HISTORICAL VALUATION BANDS" in content assert "52-week" in content or "52 week" in content assert "Average" in content or "Mean" in content assert "Current vs Historical" in content @pytest.mark.asyncio async def test_peer_valuation_comparison(self, server_with_valuation): """Test peer group valuation comparison""" company_code = "005930" result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "include_peer_comparison": True, "industry_code": "26211" # Semiconductor }) assert result is not None content = result[0].text # Should include peer comparison assert "PEER VALUATION COMPARISON" in content assert "Industry Average" in content or "Peer Average" in content assert "Percentile" in content or "Ranking" in content assert "vs Peers" in content @pytest.mark.asyncio async def test_valuation_summary_metrics(self, server_with_valuation, sample_market_data): """Test comprehensive valuation summary""" company_code = "005930" with patch.object(server_with_valuation.valuation_analyzer, 'get_market_data') as mock_market: mock_market.return_value = sample_market_data[company_code] result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "analysis_type": "comprehensive" }) assert result is not None content = result[0].text # Should include comprehensive analysis assert "VALUATION SUMMARY" in content assert "Market Capitalization" in content assert "Fair Value Range" in content or "Valuation Range" in content assert "Investment Recommendation" in content or "Valuation Assessment" in content @pytest.mark.asyncio async def test_dividend_yield_metrics(self, server_with_valuation): """Test dividend yield and payout analysis""" company_code = "005930" result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "include_dividend_analysis": True }) assert result is not None content = result[0].text # Should include dividend analysis assert "DIVIDEND ANALYSIS" in content assert "Dividend Yield" in content assert "Payout Ratio" in content assert "Dividend History" in content or "Payment History" in content @pytest.mark.asyncio async def test_valuation_metrics_error_handling(self, server_with_valuation): """Test error handling for valuation metrics""" # Test invalid company code with pytest.raises(MCPStockDetailsError): await server_with_valuation._handle_get_valuation_metrics({ "company_code": "", "include_multiples": True }) # Test insufficient market data with pytest.raises(InsufficientDataError): await server_with_valuation._handle_get_valuation_metrics({ "company_code": "999999", # Non-existent company "include_multiples": True }) @pytest.mark.asyncio async def test_valuation_metrics_output_formats(self, server_with_valuation, sample_market_data): """Test different output formats for valuation metrics""" company_code = "005930" with patch.object(server_with_valuation.valuation_analyzer, 'get_market_data') as mock_market: mock_market.return_value = sample_market_data[company_code] # Test detailed format detailed = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "output_format": "detailed" }) # Test summary format summary = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "output_format": "summary" }) assert detailed is not None and summary is not None detailed_content = detailed[0].text summary_content = summary[0].text # Detailed should be more comprehensive assert len(detailed_content) > len(summary_content) assert "DETAILED VALUATION ANALYSIS" in detailed_content assert "VALUATION SUMMARY" in summary_content @pytest.mark.asyncio async def test_valuation_metrics_performance(self, server_with_valuation, sample_market_data): """Test performance requirements for valuation metrics""" company_code = "005930" with patch.object(server_with_valuation.valuation_analyzer, 'get_market_data') as mock_market: mock_market.return_value = sample_market_data[company_code] import time start_time = time.time() result = await server_with_valuation._handle_get_valuation_metrics({ "company_code": company_code, "analysis_type": "comprehensive", "include_multiples": True, "include_ev_multiples": True, "include_historical_bands": True, "include_peer_comparison": True }) execution_time = time.time() - start_time # Should complete within 3 seconds assert execution_time < 3.0 assert result is not None # Should have processing time info content = result[0].text assert "Processing Time" in content or len(content) > 500

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/whdghk1907/mcp-stock-details'

If you have feedback or need assistance with the MCP directory API, please join our Discord server