163 lines
5.6 KiB
Python
163 lines
5.6 KiB
Python
"""Unit tests for AI analyzer"""
|
|||
|
|
import pytest
|
||
|
|
from unittest.mock import Mock, patch, MagicMock
|
||
|
|
from app.services.ai_analyzer import AIAnalyzer, ClaudeAnalyzer
|
||
|
|
from app.models.feedback import AnalysisResult
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.unit
|
||
|
|
def test_ai_analyzer_interface():
|
||
|
|
"""T065: Unit test for AIAnalyzer interface
|
||
|
|
|
||
|
|
Verify that AIAnalyzer is an abstract base class
|
||
|
|
that cannot be instantiated directly
|
||
|
|
"""
|
||
|
|
with pytest.raises(TypeError):
|
||
|
|
# Should not be able to instantiate abstract base class
|
||
|
|
AIAnalyzer()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.unit
|
||
|
|
def test_claude_analyzer_categorization(app):
|
||
|
|
"""T066: Unit test for ClaudeAnalyzer categorization
|
||
|
|
|
||
|
|
Verify that ClaudeAnalyzer correctly extracts category from AI response
|
||
|
|
"""
|
||
|
|
with app.app_context():
|
||
|
|
# Mock the Anthropic client to avoid initialization issues
|
||
|
|
with patch('app.services.ai_analyzer.anthropic.Anthropic'):
|
||
|
|
analyzer = ClaudeAnalyzer(api_key='test-key')
|
||
|
|
|
||
|
|
# Mock AI response with category
|
||
|
|
mock_response = Mock()
|
||
|
|
mock_response.content = [Mock(text="""
|
||
|
|
# Feedback Analysis
|
||
|
|
|
||
|
|
**Category**: bug
|
||
|
|
|
||
|
|
**Original Language**: en
|
||
|
|
|
||
|
|
**Summary**: User reports login issue
|
||
|
|
|
||
|
|
**Translation**: (same as original)
|
||
|
|
""")]
|
||
|
|
|
||
|
|
with patch.object(analyzer, '_call_claude_api', return_value=mock_response):
|
||
|
|
result = analyzer.analyze_feedback(
|
||
|
|
feedback_text="Login button doesn't work",
|
||
|
|
target_language='en',
|
||
|
|
product_id='test-product'
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result.category == 'bug'
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.unit
|
||
|
|
def test_claude_analyzer_translation(app):
|
||
|
|
"""T067: Unit test for ClaudeAnalyzer translation
|
||
|
|
|
||
|
|
Verify that ClaudeAnalyzer correctly translates feedback
|
||
|
|
"""
|
||
|
|
with app.app_context():
|
||
|
|
# Mock the Anthropic client to avoid initialization issues
|
||
|
|
with patch('app.services.ai_analyzer.anthropic.Anthropic'):
|
||
|
|
analyzer = ClaudeAnalyzer(api_key='test-key')
|
||
|
|
|
||
|
|
# Mock AI response with translation
|
||
|
|
mock_response = Mock()
|
||
|
|
mock_response.content = [Mock(text="""
|
||
|
|
# Feedback Analysis
|
||
|
|
|
||
|
|
**Category**: feature_request
|
||
|
|
|
||
|
|
**Original Language**: de
|
||
|
|
|
||
|
|
**Summary**: User wants dark mode
|
||
|
|
|
||
|
|
**Translation**: I would like to have a dark mode for the application
|
||
|
|
""")]
|
||
|
|
|
||
|
|
with patch.object(analyzer, '_call_claude_api', return_value=mock_response):
|
||
|
|
result = analyzer.analyze_feedback(
|
||
|
|
feedback_text="Ich hätte gerne einen Dark Mode für die Anwendung",
|
||
|
|
target_language='en',
|
||
|
|
product_id='test-product'
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result.translation == 'I would like to have a dark mode for the application'
|
||
|
|
assert result.original_language == 'de'
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.unit
|
||
|
|
def test_claude_analyzer_summary_generation(app):
|
||
|
|
"""T068: Unit test for ClaudeAnalyzer summary generation
|
||
|
|
|
||
|
|
Verify that ClaudeAnalyzer generates concise summaries
|
||
|
|
"""
|
||
|
|
with app.app_context():
|
||
|
|
# Mock the Anthropic client to avoid initialization issues
|
||
|
|
with patch('app.services.ai_analyzer.anthropic.Anthropic'):
|
||
|
|
analyzer = ClaudeAnalyzer(api_key='test-key')
|
||
|
|
|
||
|
|
# Mock AI response with summary
|
||
|
|
mock_response = Mock()
|
||
|
|
mock_response.content = [Mock(text="""
|
||
|
|
# Feedback Analysis
|
||
|
|
|
||
|
|
**Category**: complaint
|
||
|
|
|
||
|
|
**Original Language**: en
|
||
|
|
|
||
|
|
**Summary**: User experienced slow page load times during peak hours
|
||
|
|
|
||
|
|
**Translation**: (same as original)
|
||
|
|
""")]
|
||
|
|
|
||
|
|
with patch.object(analyzer, '_call_claude_api', return_value=mock_response):
|
||
|
|
long_feedback = """
|
||
|
|
I've been using your service for three months now, and I have to say
|
||
|
|
I'm quite disappointed with the performance during peak hours. Yesterday
|
||
|
|
evening around 8 PM, I tried to load the dashboard multiple times and
|
||
|
|
each time it took over 30 seconds. This is unacceptable for a paid service.
|
||
|
|
"""
|
||
|
|
|
||
|
|
result = analyzer.analyze_feedback(
|
||
|
|
feedback_text=long_feedback,
|
||
|
|
target_language='en',
|
||
|
|
product_id='test-product'
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result.summary == 'User experienced slow page load times during peak hours'
|
||
|
|
assert len(result.summary) < len(long_feedback)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.unit
|
||
|
|
def test_analysis_error_handling(app):
|
||
|
|
"""T069: Unit test for analysis error handling
|
||
|
|
|
||
|
|
Verify that ClaudeAnalyzer handles API errors gracefully
|
||
|
|
"""
|
||
|
|
with app.app_context():
|
||
|
|
# Mock the Anthropic client to avoid initialization issues
|
||
|
|
with patch('app.services.ai_analyzer.anthropic.Anthropic'):
|
||
|
|
analyzer = ClaudeAnalyzer(api_key='test-key')
|
||
|
|
|
||
|
|
# Test API timeout
|
||
|
|
with patch.object(analyzer, '_call_claude_api', side_effect=TimeoutError("API timeout")):
|
||
|
|
with pytest.raises(Exception) as exc_info:
|
||
|
|
analyzer.analyze_feedback(
|
||
|
|
feedback_text="Test feedback",
|
||
|
|
target_language='en',
|
||
|
|
product_id='test-product'
|
||
|
|
)
|
||
|
|
assert "timeout" in str(exc_info.value).lower() or "API" in str(exc_info.value)
|
||
|
|
|
||
|
|
# Test API error
|
||
|
|
with patch.object(analyzer, '_call_claude_api', side_effect=Exception("API Error")):
|
||
|
|
with pytest.raises(Exception):
|
||
|
|
analyzer.analyze_feedback(
|
||
|
|
feedback_text="Test feedback",
|
||
|
|
target_language='en',
|
||
|
|
product_id='test-product'
|
||
|
|
)
|