150 lines
6.3 KiB
JSON
150 lines
6.3 KiB
JSON
|
|
{
|
||
|
|
"task_id": "TEST-COVERAGE-SERVICES-001",
|
||
|
|
"summary": "Add PHPUnit tests for 7 critical untested services: PermissionService, RoleService, DepartmentService, TenantService, MailService, UserLifecycleService, RateLimiterService.",
|
||
|
|
"assumptions": [
|
||
|
|
"All 7 services use constructor injection and are unit-testable with mocks (GR-TEST-002 compliant).",
|
||
|
|
"Focus on happy path + at least one failure/edge case per public method (GR-TEST-001).",
|
||
|
|
"Services that orchestrate repositories will have repositories mocked.",
|
||
|
|
"MailService test will mock PHPMailer — no actual email sending."
|
||
|
|
],
|
||
|
|
"scope": {
|
||
|
|
"in": [
|
||
|
|
"New: tests/Service/Access/PermissionServiceTest.php — CRUD + permission assignment logic",
|
||
|
|
"New: tests/Service/Access/RoleServiceTest.php — CRUD + role validation",
|
||
|
|
"New: tests/Service/Org/DepartmentServiceTest.php — CRUD + hierarchy validation",
|
||
|
|
"New: tests/Service/Tenant/TenantServiceTest.php — CRUD + tenant lifecycle",
|
||
|
|
"New: tests/Service/Mail/MailServiceTest.php — composition + send + error handling",
|
||
|
|
"New: tests/Service/User/UserLifecycleServiceTest.php — state transitions (active/inactive/deleted)",
|
||
|
|
"New: tests/Service/Security/RateLimiterServiceTest.php — rate limit enforcement + reset"
|
||
|
|
],
|
||
|
|
"out": [
|
||
|
|
"Repository tests (separate task)",
|
||
|
|
"Gateway tests (separate task)",
|
||
|
|
"Integration/E2E tests",
|
||
|
|
"Production code changes (test-only task)",
|
||
|
|
"Medium/low priority untested services (BrandingService, SearchDataService, etc.)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"guardrails": {
|
||
|
|
"required_guard_ids": [
|
||
|
|
"GR-TEST-001",
|
||
|
|
"GR-TEST-002",
|
||
|
|
"GR-LANG-001",
|
||
|
|
"GR-LANG-002"
|
||
|
|
],
|
||
|
|
"required_quality_gate_ids": [
|
||
|
|
"QG-001",
|
||
|
|
"QG-002",
|
||
|
|
"QG-006"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"success_criteria": [
|
||
|
|
{
|
||
|
|
"id": "SC-001",
|
||
|
|
"criterion": "All 7 test files exist and contain at least one happy-path and one failure/edge-case test per public method of the corresponding service."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "SC-002",
|
||
|
|
"criterion": "Each test file uses proper mocking (createMock) for all injected dependencies — no real DB or HTTP calls."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "SC-003",
|
||
|
|
"criterion": "Total new test methods >= 40 across the 7 files (average ~6 per service)."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "SC-004",
|
||
|
|
"criterion": "PHPUnit full suite (QG-001) passes green including all new tests."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "SC-005",
|
||
|
|
"criterion": "PHPStan (QG-002) passes green — test files are type-safe."
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"implementation_steps": [
|
||
|
|
{
|
||
|
|
"id": "S1",
|
||
|
|
"title": "Analyze public API of all 7 services",
|
||
|
|
"description": "Read each service file, list all public methods, identify constructor dependencies, and plan test scenarios (happy path + edge cases).",
|
||
|
|
"guard_refs": ["GR-TEST-001"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S2",
|
||
|
|
"title": "Write PermissionServiceTest",
|
||
|
|
"description": "Test CRUD operations (createFromAdmin, updateFromAdmin, deleteById), permission assignment, and validation error paths.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S3",
|
||
|
|
"title": "Write RoleServiceTest",
|
||
|
|
"description": "Test CRUD operations, role validation (duplicate name, missing fields), and permission assignment.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S4",
|
||
|
|
"title": "Write DepartmentServiceTest",
|
||
|
|
"description": "Test CRUD operations, hierarchy validation, tenant scope enforcement.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S5",
|
||
|
|
"title": "Write TenantServiceTest",
|
||
|
|
"description": "Test CRUD operations, tenant lifecycle (activate/deactivate), slug generation, validation.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S6",
|
||
|
|
"title": "Write MailServiceTest",
|
||
|
|
"description": "Test email composition, recipient validation, template rendering, and error handling when SMTP fails. Mock PHPMailer.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S7",
|
||
|
|
"title": "Write UserLifecycleServiceTest",
|
||
|
|
"description": "Test state transitions: active->inactive, inactive->active, soft-delete, restore. Test audit trail calls.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S8",
|
||
|
|
"title": "Write RateLimiterServiceTest",
|
||
|
|
"description": "Test rate limit enforcement (under limit, at limit, over limit), reset, and TTL expiration.",
|
||
|
|
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "S9",
|
||
|
|
"title": "Run quality gates",
|
||
|
|
"description": "QG-001 PHPUnit full, QG-002 PHPStan, QG-006 CS check.",
|
||
|
|
"guard_refs": ["GR-LANG-002"]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"tests": [
|
||
|
|
"tests/Service/Access/PermissionServiceTest.php",
|
||
|
|
"tests/Service/Access/RoleServiceTest.php",
|
||
|
|
"tests/Service/Org/DepartmentServiceTest.php",
|
||
|
|
"tests/Service/Tenant/TenantServiceTest.php",
|
||
|
|
"tests/Service/Mail/MailServiceTest.php",
|
||
|
|
"tests/Service/User/UserLifecycleServiceTest.php",
|
||
|
|
"tests/Service/Security/RateLimiterServiceTest.php"
|
||
|
|
],
|
||
|
|
"acceptance_checks": [
|
||
|
|
"SC-001: Each test file covers every public method of its service with happy + failure paths",
|
||
|
|
"SC-002: rg 'createMock' in all 7 test files shows proper dependency mocking",
|
||
|
|
"SC-003: phpunit --list-tests | grep -c 'Test::test' for new files totals >= 40",
|
||
|
|
"SC-004: docker compose exec php vendor/bin/phpunit exits 0",
|
||
|
|
"SC-005: docker compose exec php vendor/bin/phpstan analyse exits 0"
|
||
|
|
],
|
||
|
|
"risks": [
|
||
|
|
{
|
||
|
|
"risk": "Services with complex dependencies (MailService depends on PHPMailer, SMTP config) may be hard to mock",
|
||
|
|
"mitigation": "Use interface-based mocking. If PHPMailer is used directly, mock at the gateway boundary instead."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"risk": "UserLifecycleService may have implicit state dependencies (session, tenant context)",
|
||
|
|
"mitigation": "Analyze constructor carefully. Mock all injected gateways/services. If static state access exists, document as tech debt for later refactor."
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"risk": "Scope creep — discovering untestable code that needs refactoring",
|
||
|
|
"mitigation": "Document untestable patterns as findings but do NOT refactor production code in this task. Create follow-up tasks instead."
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|