08ea5fbe98
添加用户管理视图、API和状态管理文件
506 lines
17 KiB
Python
506 lines
17 KiB
Python
import pytest
|
|
from unittest.mock import MagicMock, patch
|
|
from datetime import datetime
|
|
from apitest.models.test_models import (
|
|
TestCase, TestResult, TestSuiteResult, HTTPMethod, PerformanceMetrics
|
|
)
|
|
from apitest.core.test_engine import TestEngine
|
|
from apitest.core.validation_engine import ValidationEngine
|
|
from apitest.models.exceptions import TestRunException
|
|
|
|
|
|
class TestTestEngine:
|
|
"""测试TestEngine测试引擎"""
|
|
|
|
@pytest.fixture
|
|
def mock_api_client(self):
|
|
"""模拟API客户端"""
|
|
api_client = MagicMock()
|
|
api_client.request.return_value = {
|
|
"status_code": 200,
|
|
"response_body": {"message": "success"},
|
|
"response_headers": {"Content-Type": "application/json"},
|
|
"performance": PerformanceMetrics(
|
|
timestamp=datetime.now(),
|
|
response_time=1000,
|
|
request_size=100,
|
|
response_size=200
|
|
)
|
|
}
|
|
return api_client
|
|
|
|
@pytest.fixture
|
|
def mock_auth_manager(self):
|
|
"""模拟认证管理器"""
|
|
auth_manager = MagicMock()
|
|
auth_manager.get_auth_headers.return_value = {"Authorization": "Bearer token"}
|
|
return auth_manager
|
|
|
|
@pytest.fixture
|
|
def mock_validation_engine(self):
|
|
"""模拟验证引擎"""
|
|
validation_engine = MagicMock()
|
|
validation_engine.validate_response.return_value = (True, "")
|
|
return validation_engine
|
|
|
|
@pytest.fixture
|
|
def test_engine(self, mock_api_client, mock_auth_manager, mock_validation_engine):
|
|
"""创建测试引擎实例"""
|
|
return TestEngine(
|
|
api_client=mock_api_client,
|
|
auth_manager=mock_auth_manager,
|
|
validation_engine=mock_validation_engine
|
|
)
|
|
|
|
def test_test_engine_initialization(self, test_engine):
|
|
"""测试测试引擎初始化"""
|
|
assert test_engine.api_client is not None
|
|
assert test_engine.auth_manager is not None
|
|
assert test_engine.validation_engine is not None
|
|
assert test_engine._context == {}
|
|
|
|
def test_set_context(self, test_engine):
|
|
"""测试设置上下文变量"""
|
|
test_engine.set_context("user_id", "12345")
|
|
assert test_engine.get_context("user_id") == "12345"
|
|
|
|
def test_get_context_with_default(self, test_engine):
|
|
"""测试获取上下文变量(带默认值)"""
|
|
assert test_engine.get_context("nonexistent", "default") == "default"
|
|
|
|
def test_topological_sort_no_dependencies(self, test_engine):
|
|
"""测试拓扑排序(无依赖)"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
)
|
|
]
|
|
|
|
sorted_cases = test_engine._topological_sort(test_cases)
|
|
assert len(sorted_cases) == 2
|
|
|
|
def test_topological_sort_with_dependencies(self, test_engine):
|
|
"""测试拓扑排序(有依赖)"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=[]
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=["TC001"]
|
|
),
|
|
TestCase(
|
|
id="TC003",
|
|
name="测试3",
|
|
description="测试用例3",
|
|
module="test",
|
|
endpoint="/api/test3",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=["TC002"]
|
|
)
|
|
]
|
|
|
|
sorted_cases = test_engine._topological_sort(test_cases)
|
|
assert len(sorted_cases) == 3
|
|
assert sorted_cases[0].id == "TC001"
|
|
assert sorted_cases[1].id == "TC002"
|
|
assert sorted_cases[2].id == "TC003"
|
|
|
|
def test_topological_sort_circular_dependency(self, test_engine):
|
|
"""测试拓扑排序(循环依赖)"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=["TC002"]
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=["TC001"]
|
|
)
|
|
]
|
|
|
|
with pytest.raises(TestRunException, match="存在循环依赖"):
|
|
test_engine._topological_sort(test_cases)
|
|
|
|
def test_resolve_context_variables_string(self, test_engine):
|
|
"""测试解析上下文变量(字符串)"""
|
|
test_engine.set_context("user_id", "12345")
|
|
result = test_engine._resolve_context_variables("${user_id}")
|
|
assert result == "12345"
|
|
|
|
def test_resolve_context_variables_dict(self, test_engine):
|
|
"""测试解析上下文变量(字典)"""
|
|
test_engine.set_context("user_id", "12345")
|
|
data = {"user_id": "${user_id}", "name": "test"}
|
|
result = test_engine._resolve_context_variables(data)
|
|
assert result == {"user_id": "12345", "name": "test"}
|
|
|
|
def test_resolve_context_variables_list(self, test_engine):
|
|
"""测试解析上下文变量(列表)"""
|
|
test_engine.set_context("user_id", "12345")
|
|
data = ["${user_id}", "test"]
|
|
result = test_engine._resolve_context_variables(data)
|
|
assert result == ["12345", "test"]
|
|
|
|
def test_execute_test_case_success(self, test_engine):
|
|
"""测试执行测试用例(成功)"""
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
validations=[{"type": "status_code", "value": 200}]
|
|
)
|
|
|
|
result = test_engine._execute_test_case(test_case)
|
|
|
|
assert isinstance(result, TestResult)
|
|
assert result.passed == True
|
|
assert result.status_code == 200
|
|
assert result.test_case == test_case
|
|
|
|
def test_execute_test_case_with_auth(self, test_engine):
|
|
"""测试执行测试用例(带认证)"""
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
auth_required=True
|
|
)
|
|
|
|
result = test_engine._execute_test_case(test_case)
|
|
|
|
assert result.passed == True
|
|
test_engine.auth_manager.get_auth_headers.assert_called_once()
|
|
|
|
def test_execute_test_case_failure(self, test_engine, mock_validation_engine):
|
|
"""测试执行测试用例(失败)"""
|
|
mock_validation_engine.validate_response.return_value = (False, "验证失败")
|
|
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
validations=[{"type": "status_code", "value": 200}]
|
|
)
|
|
|
|
result = test_engine._execute_test_case(test_case)
|
|
|
|
assert result.passed == False
|
|
assert result.error_message == "验证失败"
|
|
|
|
def test_execute_test_case_with_setup(self, test_engine):
|
|
"""测试执行测试用例(带前置操作)"""
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
setup={"type": "set_context", "key": "test_key", "value": "test_value"}
|
|
)
|
|
|
|
result = test_engine._execute_test_case(test_case)
|
|
|
|
assert test_engine.get_context("test_key") == "test_value"
|
|
|
|
def test_execute_test_case_with_teardown(self, test_engine):
|
|
"""测试执行测试用例(带后置操作)"""
|
|
test_engine.set_context("test_key", "test_value")
|
|
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
teardown={"type": "clear_context", "key": "test_key"}
|
|
)
|
|
|
|
result = test_engine._execute_test_case(test_case)
|
|
|
|
assert test_engine.get_context("test_key") is None
|
|
|
|
def test_execute_test_suite(self, test_engine):
|
|
"""测试执行测试套件"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_suite(test_cases)
|
|
|
|
assert isinstance(result, TestSuiteResult)
|
|
assert len(result.results) == 2
|
|
assert result.passed == 2
|
|
assert result.failed == 0
|
|
|
|
def test_execute_test_suite_with_dependencies(self, test_engine):
|
|
"""测试执行测试套件(有依赖)"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=[]
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
dependencies=["TC001"]
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_suite(test_cases)
|
|
|
|
assert len(result.results) == 2
|
|
assert result.passed == 2
|
|
|
|
def test_execute_test_suite_stop_on_failure(self, test_engine, mock_validation_engine):
|
|
"""测试执行测试套件(失败时停止)"""
|
|
mock_validation_engine.validate_response.return_value = (False, "验证失败")
|
|
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_suite(test_cases, stop_on_failure=True)
|
|
|
|
assert len(result.results) == 1
|
|
assert result.passed == 0
|
|
assert result.failed == 1
|
|
|
|
def test_execute_test_suite_skip_disabled(self, test_engine):
|
|
"""测试执行测试套件(跳过已禁用的用例)"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
enabled=False
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
enabled=True
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_suite(test_cases)
|
|
|
|
assert len(result.results) == 1
|
|
assert result.skipped == 1
|
|
|
|
def test_execute_test_cases_by_filter_module(self, test_engine):
|
|
"""测试按模块过滤执行测试用例"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="module1",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="module2",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={}
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_cases_by_filter(test_cases, module_filter="module1")
|
|
|
|
assert len(result.results) == 1
|
|
assert result.results[0].test_case.module == "module1"
|
|
|
|
def test_execute_test_cases_by_filter_tag(self, test_engine):
|
|
"""测试按标签过滤执行测试用例"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
tags=["smoke", "regression"]
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
tags=["regression"]
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_cases_by_filter(test_cases, tag_filter=["smoke"])
|
|
|
|
assert len(result.results) == 1
|
|
assert "smoke" in result.results[0].test_case.tags
|
|
|
|
def test_execute_test_cases_by_filter_priority(self, test_engine):
|
|
"""测试按优先级过滤执行测试用例"""
|
|
test_cases = [
|
|
TestCase(
|
|
id="TC001",
|
|
name="测试1",
|
|
description="测试用例1",
|
|
module="test",
|
|
endpoint="/api/test1",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
priority=1
|
|
),
|
|
TestCase(
|
|
id="TC002",
|
|
name="测试2",
|
|
description="测试用例2",
|
|
module="test",
|
|
endpoint="/api/test2",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
priority=2
|
|
)
|
|
]
|
|
|
|
result = test_engine.execute_test_cases_by_filter(test_cases, priority_filter=1)
|
|
|
|
assert len(result.results) == 1
|
|
assert result.results[0].test_case.priority == 1
|
|
|
|
def test_extract_response_data(self, test_engine):
|
|
"""测试提取响应数据到上下文"""
|
|
test_case = TestCase(
|
|
id="TC001",
|
|
name="测试用例",
|
|
description="测试用例描述",
|
|
module="test",
|
|
endpoint="/api/test",
|
|
method=HTTPMethod.GET,
|
|
headers={},
|
|
validations=[{"type": "extract", "field": "user_id", "var_name": "extracted_id"}]
|
|
)
|
|
|
|
response_body = {"user_id": "12345", "name": "test"}
|
|
test_engine._extract_response_data(test_case, response_body)
|
|
|
|
assert test_engine.get_context("extracted_id") == "12345"
|