diff --git a/tests/test_tools_controller.py b/tests/test_tools_controller.py index a313e1c..806a0b3 100644 --- a/tests/test_tools_controller.py +++ b/tests/test_tools_controller.py @@ -4,6 +4,7 @@ from fastapi.testclient import TestClient from unittest.mock import patch, AsyncMock, MagicMock from src.main import app +from src.domains.tools.controller import tools_controller @pytest.fixture @@ -36,9 +37,21 @@ class TestDNSLookup: ) assert response.status_code == 200 - @patch("src.controllers.tools_controller.DNSService") - def test_dns_lookup_returns_result(self, mock_dns_class, client): - """DNS lookup should return lookup results.""" + def test_dns_lookup_returns_result(self, client): + """DNS lookup should return lookup results. + + Patches the live singleton's `dns_service` attribute, not the + `src.controllers.tools_controller.DNSService` class: that module is + the legacy top-level package (not wired into `src.main`, see + CLAUDE.md "Legacy top-level packages"). `client` exercises + `src.main.app`, which routes through + `src.domains.tools.controller.tools_controller`, a singleton built + at import time — so patching the class there would also miss, + since `tools_controller.dns_service` is already a constructed + instance by the time a test patches the class. Patching the + instance attribute directly is the only patch that actually + intercepts this request path. + """ mock_response = MagicMock() mock_response.success = True mock_response.domain = "example.com" @@ -59,12 +72,12 @@ class TestDNSLookup: mock_service = MagicMock() mock_service.lookup = AsyncMock(return_value=mock_response) - mock_dns_class.return_value = mock_service - response = client.post( - "/tools/dns/lookup", - json={"domain": "example.com", "record_type": "A"} - ) + with patch.object(tools_controller, "dns_service", mock_service): + response = client.post( + "/tools/dns/lookup", + json={"domain": "example.com", "record_type": "A"} + ) data = response.json() assert data["success"] is True