test_esg_info.pyβ’12.4 kB
"""
Unit tests for ESG (Environmental, Social, Governance) information functionality
TDD Red Phase: Write failing tests for ESG 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.esg_tools import ESGAnalyzer
from src.exceptions import MCPStockDetailsError, InsufficientDataError
class TestESGInfo:
"""Test cases for ESG information functionality"""
@pytest.fixture
def server_with_esg(self):
"""Create server instance with ESG analyzer"""
server = MCPStockDetailsServer()
# This will fail initially - Red phase
server.esg_analyzer = ESGAnalyzer()
return server
@pytest.fixture
def sample_esg_data(self):
"""Sample ESG data for testing"""
return {
"005930": { # Samsung Electronics
"esg_scores": {
"environmental": {
"score": 82.5,
"grade": "A",
"carbon_emissions": 12500000, # tCO2e
"renewable_energy_percent": 45.2,
"water_usage": 152000000, # cubic meters
"waste_recycling_rate": 92.3
},
"social": {
"score": 78.3,
"grade": "B+",
"employee_satisfaction": 4.2, # out of 5
"gender_diversity_ratio": 0.35,
"safety_incidents": 12,
"community_investment": 125000000000 # KRW
},
"governance": {
"score": 85.7,
"grade": "A",
"board_independence_ratio": 0.67,
"ethics_violations": 2,
"ceo_pay_ratio": 52.3,
"shareholder_rights_score": 88.5
},
"total_score": 82.2,
"total_grade": "A-",
"last_updated": "2024-01-15"
},
"esg_initiatives": [
{
"category": "environmental",
"title": "RE100 Commitment",
"description": "Target 100% renewable energy by 2025",
"impact": "Reduce carbon emissions by 5M tons annually"
},
{
"category": "social",
"title": "Digital Education Program",
"description": "STEM education for 1M students",
"impact": "Enhanced tech literacy in 50 countries"
}
],
"esg_risks": [
{
"type": "environmental",
"risk": "Supply chain carbon footprint",
"severity": "medium",
"mitigation": "Supplier sustainability program"
},
{
"type": "governance",
"risk": "Regulatory compliance in emerging markets",
"severity": "low",
"mitigation": "Enhanced compliance monitoring system"
}
]
}
}
@pytest.mark.asyncio
async def test_get_esg_info_tool_registration(self, server_with_esg):
"""Test that get_esg_info tool is properly registered"""
tools = await server_with_esg.list_tools()
tool_names = [tool.name for tool in tools]
assert "get_esg_info" in tool_names
# Check tool description and parameters
esg_tool = next(tool for tool in tools if tool.name == "get_esg_info")
assert "esg" in esg_tool.description.lower()
assert "environmental" in esg_tool.description.lower()
assert "company_code" in esg_tool.inputSchema["properties"]
@pytest.mark.asyncio
async def test_basic_esg_scores(self, server_with_esg, sample_esg_data):
"""Test basic ESG scores retrieval"""
company_code = "005930"
with patch.object(server_with_esg.esg_analyzer, 'get_esg_data') as mock_esg:
mock_esg.return_value = sample_esg_data[company_code]
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_scores": True
})
assert result is not None
assert len(result) > 0
content = result[0].text
# Should include ESG scores
assert "ESG SCORES" in content
assert "Environmental" in content
assert "Social" in content
assert "Governance" in content
assert "82.5" in content # Environmental score
assert "Grade: A" in content
@pytest.mark.asyncio
async def test_detailed_environmental_metrics(self, server_with_esg, sample_esg_data):
"""Test detailed environmental metrics"""
company_code = "005930"
with patch.object(server_with_esg.esg_analyzer, 'get_esg_data') as mock_esg:
mock_esg.return_value = sample_esg_data[company_code]
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_environmental_details": True
})
assert result is not None
content = result[0].text
# Should include environmental details
assert "ENVIRONMENTAL METRICS" in content
assert "Carbon Emissions" in content
assert "Renewable Energy" in content
assert "Water Usage" in content
assert "Waste Recycling" in content
assert "45.2%" in content # Renewable energy percent
@pytest.mark.asyncio
async def test_social_responsibility_metrics(self, server_with_esg):
"""Test social responsibility metrics"""
company_code = "005930"
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_social_details": True
})
assert result is not None
content = result[0].text
# Should include social metrics
assert "SOCIAL RESPONSIBILITY" in content
assert "Employee Satisfaction" in content
assert "Gender Diversity" in content
assert "Safety" in content
assert "Community Investment" in content
@pytest.mark.asyncio
async def test_governance_metrics(self, server_with_esg):
"""Test governance metrics"""
company_code = "005930"
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_governance_details": True
})
assert result is not None
content = result[0].text
# Should include governance metrics
assert "GOVERNANCE METRICS" in content
assert "Board Independence" in content
assert "Ethics" in content
assert "CEO Pay Ratio" in content
assert "Shareholder Rights" in content
@pytest.mark.asyncio
async def test_esg_initiatives_tracking(self, server_with_esg, sample_esg_data):
"""Test ESG initiatives tracking"""
company_code = "005930"
with patch.object(server_with_esg.esg_analyzer, 'get_esg_data') as mock_esg:
mock_esg.return_value = sample_esg_data[company_code]
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_initiatives": True
})
assert result is not None
content = result[0].text
# Should include ESG initiatives
assert "ESG INITIATIVES" in content
assert "RE100 Commitment" in content
assert "Digital Education Program" in content
assert "Impact" in content
@pytest.mark.asyncio
async def test_esg_risk_assessment(self, server_with_esg, sample_esg_data):
"""Test ESG risk assessment"""
company_code = "005930"
with patch.object(server_with_esg.esg_analyzer, 'get_esg_data') as mock_esg:
mock_esg.return_value = sample_esg_data[company_code]
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_risks": True
})
assert result is not None
content = result[0].text
# Should include ESG risks
assert "ESG RISKS" in content
assert "Supply chain carbon footprint" in content
assert "Severity" in content
assert "Mitigation" in content
@pytest.mark.asyncio
async def test_esg_peer_comparison(self, server_with_esg):
"""Test ESG peer comparison"""
company_code = "005930"
result = await server_with_esg._handle_get_esg_info({
"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 "ESG PEER COMPARISON" in content
assert "Industry Average" in content
assert "Ranking" in content
assert "vs Peers" in content
@pytest.mark.asyncio
async def test_esg_trend_analysis(self, server_with_esg):
"""Test ESG trend analysis over time"""
company_code = "005930"
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"include_trends": True,
"trend_period": "3Y"
})
assert result is not None
content = result[0].text
# Should include trend analysis
assert "ESG TREND ANALYSIS" in content
assert "3-Year Trend" in content
assert "Improvement" in content or "Change" in content
assert "Historical Performance" in content
@pytest.mark.asyncio
async def test_esg_comprehensive_report(self, server_with_esg, sample_esg_data):
"""Test comprehensive ESG report generation"""
company_code = "005930"
with patch.object(server_with_esg.esg_analyzer, 'get_esg_data') as mock_esg:
mock_esg.return_value = sample_esg_data[company_code]
result = await server_with_esg._handle_get_esg_info({
"company_code": company_code,
"report_type": "comprehensive"
})
assert result is not None
content = result[0].text
# Should include all major sections
assert "ESG COMPREHENSIVE REPORT" in content
assert "Overall ESG Rating" in content
assert "82.2" in content # Total score
assert "Grade: A-" in content
assert "Key Strengths" in content
assert "Areas for Improvement" in content
@pytest.mark.asyncio
async def test_esg_error_handling(self, server_with_esg):
"""Test error handling for ESG information"""
# Test invalid company code
with pytest.raises(MCPStockDetailsError):
await server_with_esg._handle_get_esg_info({
"company_code": "",
"include_scores": True
})
# Test unavailable ESG data
with pytest.raises(InsufficientDataError):
await server_with_esg._handle_get_esg_info({
"company_code": "999999", # Non-existent company
"include_scores": True
})