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"