280 lines
9.3 KiB
Python
280 lines
9.3 KiB
Python
"""
|
|
满意度调查服务测试用例
|
|
|
|
测试覆盖:
|
|
1. 问卷管理功能
|
|
2. 题目管理功能
|
|
3. 回答提交功能
|
|
4. 统计分析功能
|
|
"""
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
from datetime import datetime
|
|
|
|
from app.services.survey_service import SurveyService
|
|
from app.models.models import (
|
|
Survey, SurveyQuestion, SurveyResponse, SurveyAnswer,
|
|
SurveyStatus, SurveyType, QuestionType
|
|
)
|
|
|
|
|
|
class TestSurveyManagement:
|
|
"""问卷管理测试"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_survey(self):
|
|
"""测试创建问卷"""
|
|
mock_db = AsyncMock()
|
|
|
|
# 模拟数据库操作
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.survey_name = "测试问卷"
|
|
survey.survey_code = "TEST_001"
|
|
survey.survey_type = SurveyType.INPATIENT
|
|
survey.status = SurveyStatus.DRAFT
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=None):
|
|
with patch.object(SurveyService, 'get_survey_list', return_value=([], 0)):
|
|
result = await SurveyService.create_survey(
|
|
mock_db,
|
|
survey_name="测试问卷",
|
|
survey_code="TEST_001",
|
|
survey_type=SurveyType.INPATIENT
|
|
)
|
|
|
|
mock_db.add.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_publish_survey(self):
|
|
"""测试发布问卷"""
|
|
mock_db = AsyncMock()
|
|
|
|
# 创建模拟问卷
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.DRAFT
|
|
survey.total_questions = 5
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
result = await SurveyService.publish_survey(mock_db, 1)
|
|
|
|
assert survey.status == SurveyStatus.PUBLISHED
|
|
mock_db.flush.assert_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_publish_survey_without_questions(self):
|
|
"""测试发布无题目的问卷(应失败)"""
|
|
mock_db = AsyncMock()
|
|
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.DRAFT
|
|
survey.total_questions = 0
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
with pytest.raises(ValueError, match="问卷没有题目"):
|
|
await SurveyService.publish_survey(mock_db, 1)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_close_survey(self):
|
|
"""测试结束问卷"""
|
|
mock_db = AsyncMock()
|
|
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.PUBLISHED
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
result = await SurveyService.close_survey(mock_db, 1)
|
|
|
|
assert survey.status == SurveyStatus.CLOSED
|
|
|
|
|
|
class TestQuestionManagement:
|
|
"""题目管理测试"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_question(self):
|
|
"""测试添加题目"""
|
|
mock_db = AsyncMock()
|
|
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.DRAFT
|
|
survey.total_questions = 0
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
# 模拟查询最大排序号
|
|
mock_result = MagicMock()
|
|
mock_result.scalar.return_value = None
|
|
|
|
with patch('app.services.survey_service.select') as mock_select:
|
|
mock_db.execute.return_value = mock_result
|
|
|
|
result = await SurveyService.add_question(
|
|
mock_db,
|
|
survey_id=1,
|
|
question_text="您对服务是否满意?",
|
|
question_type=QuestionType.SCORE
|
|
)
|
|
|
|
mock_db.add.assert_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_add_question_to_published_survey(self):
|
|
"""测试向已发布问卷添加题目(应失败)"""
|
|
mock_db = AsyncMock()
|
|
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.PUBLISHED
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
with pytest.raises(ValueError, match="只有草稿状态的问卷可以添加题目"):
|
|
await SurveyService.add_question(
|
|
mock_db,
|
|
survey_id=1,
|
|
question_text="测试题目",
|
|
question_type=QuestionType.SCORE
|
|
)
|
|
|
|
|
|
class TestResponseSubmission:
|
|
"""回答提交测试"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_submit_response(self):
|
|
"""测试提交问卷回答"""
|
|
mock_db = AsyncMock()
|
|
|
|
# 创建模拟问卷
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.PUBLISHED
|
|
|
|
# 创建模拟题目
|
|
question = MagicMock()
|
|
question.id = 1
|
|
question.question_type = QuestionType.SCORE
|
|
question.score_max = 5
|
|
question.options = None
|
|
|
|
# 设置mock返回值
|
|
mock_q_result = MagicMock()
|
|
mock_q_result.scalar_one_or_none.return_value = question
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
with patch('app.services.survey_service.select') as mock_select:
|
|
mock_db.execute.return_value = mock_q_result
|
|
|
|
result = await SurveyService.submit_response(
|
|
mock_db,
|
|
survey_id=1,
|
|
department_id=1,
|
|
answers=[
|
|
{"question_id": 1, "answer_value": "4"}
|
|
]
|
|
)
|
|
|
|
mock_db.add.assert_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_submit_response_to_closed_survey(self):
|
|
"""测试向已结束问卷提交回答(应失败)"""
|
|
mock_db = AsyncMock()
|
|
|
|
survey = MagicMock()
|
|
survey.id = 1
|
|
survey.status = SurveyStatus.CLOSED
|
|
|
|
with patch.object(SurveyService, 'get_survey_by_id', return_value=survey):
|
|
with pytest.raises(ValueError, match="问卷未发布或已结束"):
|
|
await SurveyService.submit_response(
|
|
mock_db,
|
|
survey_id=1,
|
|
department_id=1,
|
|
answers=[]
|
|
)
|
|
|
|
|
|
class TestSatisfactionStats:
|
|
"""满意度统计测试"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_department_satisfaction(self):
|
|
"""测试获取科室满意度统计"""
|
|
mock_db = AsyncMock()
|
|
|
|
# 模拟查询结果
|
|
mock_result = MagicMock()
|
|
mock_row = MagicMock()
|
|
mock_row.department_id = 1
|
|
mock_row.department_name = "内科"
|
|
mock_row.response_count = 10
|
|
mock_row.avg_satisfaction = 85.5
|
|
mock_row.total_score = 850.0
|
|
mock_row.max_score = 1000.0
|
|
mock_result.fetchall.return_value = [mock_row]
|
|
|
|
with patch('app.services.survey_service.select') as mock_select:
|
|
mock_db.execute.return_value = mock_result
|
|
|
|
result = await SurveyService.get_department_satisfaction(
|
|
mock_db,
|
|
survey_id=1
|
|
)
|
|
|
|
assert len(result) == 1
|
|
assert result[0]["department_name"] == "内科"
|
|
assert result[0]["avg_satisfaction"] == 85.5
|
|
|
|
|
|
class TestQuestionTypes:
|
|
"""不同题型测试"""
|
|
|
|
def test_score_question_options(self):
|
|
"""测试评分题选项"""
|
|
question = MagicMock()
|
|
question.question_type = QuestionType.SCORE
|
|
question.score_max = 5
|
|
question.options = None # 评分题不需要选项
|
|
|
|
# 评分题不需要选项
|
|
assert question.options is None
|
|
|
|
def test_single_choice_options(self):
|
|
"""测试单选题选项"""
|
|
import json
|
|
|
|
options = [
|
|
{"label": "非常满意", "value": "5", "score": 5},
|
|
{"label": "满意", "value": "4", "score": 4},
|
|
{"label": "一般", "value": "3", "score": 3},
|
|
{"label": "不满意", "value": "2", "score": 2}
|
|
]
|
|
|
|
question = MagicMock()
|
|
question.question_type = QuestionType.SINGLE_CHOICE
|
|
question.options = json.dumps(options, ensure_ascii=False)
|
|
|
|
parsed_options = json.loads(question.options)
|
|
assert len(parsed_options) == 4
|
|
|
|
def test_multiple_choice_options(self):
|
|
"""测试多选题选项"""
|
|
import json
|
|
|
|
options = [
|
|
{"label": "选项A", "value": "a", "score": 1},
|
|
{"label": "选项B", "value": "b", "score": 1},
|
|
{"label": "选项C", "value": "c", "score": 1}
|
|
]
|
|
|
|
question = MagicMock()
|
|
question.question_type = QuestionType.MULTIPLE_CHOICE
|
|
question.options = json.dumps(options, ensure_ascii=False)
|
|
|
|
parsed_options = json.loads(question.options)
|
|
assert len(parsed_options) == 3
|