chartbastan/backend/tests/test_sentiment_worker.py
2026-02-01 09:31:38 +01:00

252 lines
7.9 KiB
Python

"""
Tests for sentiment analysis worker.
"""
import pytest
from unittest.mock import Mock, patch
from sqlalchemy.orm import Session
from app.workers.sentiment_worker import (
SentimentWorker,
create_sentiment_worker
)
class TestSentimentWorker:
"""Tests for SentimentWorker class."""
def test_initialization(self):
"""Test sentiment worker initialization."""
worker = SentimentWorker()
# No specific initialization required for sentiment worker
assert worker is not None
@patch('app.workers.sentiment_worker.process_tweet_batch')
@patch('app.workers.sentiment_worker.get_sentiment_by_entity')
def test_execute_sentiment_analysis_task_twitter(
self,
mock_get_sentiment,
mock_process_batch
):
"""Test executing a Twitter sentiment analysis task."""
# Create worker
worker = SentimentWorker()
# Mock database session
mock_db = Mock(spec=Session)
# Mock tweet query
mock_tweets = [Mock()] * 100
mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
# Mock existing sentiment (none exist)
mock_get_sentiment.return_value = None
# Mock batch processing
mock_process_batch.return_value = [Mock()] * 100
# Mock calculate metrics
with patch.object(
worker,
'_calculate_sentiment_metrics',
return_value={
'total_count': 100,
'positive_count': 60,
'negative_count': 20,
'neutral_count': 20,
'average_compound': 0.35
}
):
# Execute task
task = {
'match_id': 123,
'source': 'twitter',
'entity_ids': ['tweet1', 'tweet2']
}
result = worker.execute_sentiment_analysis_task(task, mock_db)
# Verify result
assert result['analyzed_count'] == 100
assert result['status'] == 'success'
assert result['metrics']['total_count'] == 100
assert result['metrics']['positive_count'] == 60
@patch('app.workers.sentiment_worker.process_reddit_post_batch')
@patch('app.workers.sentiment_worker.get_sentiment_by_entity')
def test_execute_sentiment_analysis_task_reddit(
self,
mock_get_sentiment,
mock_process_batch
):
"""Test executing a Reddit sentiment analysis task."""
# Create worker
worker = SentimentWorker()
# Mock database session
mock_db = Mock(spec=Session)
# Mock Reddit post query
mock_posts = [Mock()] * 50
mock_db.query.return_value.filter.return_value.all.return_value = mock_posts
# Mock existing sentiment (none exist)
mock_get_sentiment.return_value = None
# Mock batch processing
mock_process_batch.return_value = [Mock()] * 50
# Mock calculate metrics
with patch.object(
worker,
'_calculate_sentiment_metrics',
return_value={
'total_count': 50,
'positive_count': 25,
'negative_count': 15,
'neutral_count': 10,
'average_compound': 0.2
}
):
# Execute task
task = {
'match_id': 456,
'source': 'reddit',
'entity_ids': ['post1', 'post2']
}
result = worker.execute_sentiment_analysis_task(task, mock_db)
# Verify result
assert result['analyzed_count'] == 50
assert result['status'] == 'success'
assert result['metrics']['total_count'] == 50
@patch('app.workers.sentiment_worker.get_sentiment_by_entity')
def test_execute_sentiment_analysis_task_all_analyzed(
self,
mock_get_sentiment
):
"""Test executing task when all items already analyzed."""
worker = SentimentWorker()
mock_db = Mock(spec=Session)
# Mock tweets
mock_tweets = [Mock()] * 100
mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
# Mock existing sentiment (all exist)
mock_get_sentiment.return_value = Mock()
# Mock calculate metrics from existing
with patch.object(
worker,
'_calculate_metrics_from_existing',
return_value={
'total_count': 100,
'average_compound': 0.4
}
):
# Execute task
task = {
'match_id': 123,
'source': 'twitter',
'entity_ids': ['tweet1', 'tweet2']
}
result = worker.execute_sentiment_analysis_task(task, mock_db)
# Verify result (0 new items analyzed)
assert result['analyzed_count'] == 0
assert result['status'] == 'success'
def test_execute_sentiment_analysis_task_unknown_source(self):
"""Test executing task with unknown source."""
worker = SentimentWorker()
mock_db = Mock(spec=Session)
# Execute task with unknown source
task = {
'match_id': 123,
'source': 'unknown',
'entity_ids': ['item1']
}
result = worker.execute_sentiment_analysis_task(task, mock_db)
# Verify error result
assert result['analyzed_count'] == 0
assert result['status'] == 'error'
assert 'error' in result
assert 'Unknown source' in result['error']
@patch('app.workers.sentiment_worker.process_tweet_batch')
@patch('app.workers.sentiment_worker.get_sentiment_by_entity')
def test_execute_sentiment_analysis_task_error_handling(
self,
mock_get_sentiment,
mock_process_batch
):
"""Test error handling in sentiment analysis."""
worker = SentimentWorker()
mock_db = Mock(spec=Session)
# Mock tweets
mock_tweets = [Mock()] * 10
mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
# Mock no existing sentiment
mock_get_sentiment.return_value = None
# Mock processing error
mock_process_batch.side_effect = Exception("Processing error")
# Execute task
task = {
'match_id': 123,
'source': 'twitter',
'entity_ids': ['tweet1', 'tweet2']
}
result = worker.execute_sentiment_analysis_task(task, mock_db)
# Verify error handling
assert result['analyzed_count'] == 0
assert result['status'] == 'error'
assert 'error' in result
@patch('app.workers.sentiment_worker.get_sentiment_by_entity')
def test_execute_twitter_sentiment_analysis_no_tweets(
self,
mock_get_sentiment
):
"""Test Twitter sentiment analysis when no tweets found."""
worker = SentimentWorker()
mock_db = Mock(spec=Session)
# Mock no tweets
mock_db.query.return_value.filter.return_value.all.return_value = []
# Execute task
result = worker._execute_twitter_sentiment_analysis(
match_id=123,
entity_ids=['tweet1', 'tweet2'],
db=mock_db
)
# Verify result
assert result['analyzed_count'] == 0
assert result['status'] == 'success'
assert result['metrics']['total_count'] == 0
class TestCreateSentimentWorker:
"""Tests for create_sentiment_worker factory function."""
def test_create_sentiment_worker(self):
"""Test creating a sentiment worker."""
worker = create_sentiment_worker()
assert isinstance(worker, SentimentWorker)