aiox-core 5.0.7 → 5.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aiox-core/cli/commands/pro/buyer.js +379 -0
- package/.aiox-core/cli/commands/pro/index.js +191 -52
- package/.aiox-core/cli/commands/validate/index.js +2 -0
- package/.aiox-core/core/code-intel/helpers/dev-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/devops-helper.js +0 -1
- package/.aiox-core/core/code-intel/helpers/planning-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/qa-helper.js +2 -2
- package/.aiox-core/core/config/schemas/framework-config.schema.json +1 -0
- package/.aiox-core/core/config/template-overrides.js +1 -1
- package/.aiox-core/core/doctor/checks/ide-sync.js +81 -25
- package/.aiox-core/core/doctor/checks/rules-files.js +0 -1
- package/.aiox-core/core/doctor/checks/skills-count.js +83 -15
- package/.aiox-core/core/graph-dashboard/cli.js +1 -2
- package/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
- package/.aiox-core/core/ids/layer-classifier.js +1 -1
- package/.aiox-core/core/pro/pro-updater.js +578 -0
- package/.aiox-core/core/synapse/context/context-tracker.js +107 -9
- package/.aiox-core/core/synapse/layers/layer-processor.js +1 -1
- package/.aiox-core/core-config.yaml +15 -1
- package/.aiox-core/data/capability-detection.js +15 -15
- package/.aiox-core/data/entity-registry.yaml +18 -2
- package/.aiox-core/data/registry-update-log.jsonl +5 -0
- package/.aiox-core/data/tok3-token-comparison.js +0 -4
- package/.aiox-core/data/tool-search-validation.js +1 -1
- package/.aiox-core/development/agents/aiox-master.md +44 -6
- package/.aiox-core/development/agents/data-engineer.md +4 -4
- package/.aiox-core/development/agents/devops.md +52 -2
- package/.aiox-core/development/agents/po.md +1 -1
- package/.aiox-core/development/agents/qa.md +5 -11
- package/.aiox-core/development/agents/sm.md +3 -3
- package/.aiox-core/development/agents/ux-design-expert.md +1 -1
- package/.aiox-core/development/scripts/unified-activation-pipeline.js +29 -3
- package/.aiox-core/development/tasks/dev-develop-story.md +46 -7
- package/.aiox-core/development/tasks/devops-pro-access-grant.md +93 -0
- package/.aiox-core/development/tasks/devops-pro-activate.md +42 -0
- package/.aiox-core/development/tasks/devops-pro-check-access.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-request-reset.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-resend-verification.md +32 -0
- package/.aiox-core/development/tasks/devops-pro-reset-password.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-validate-login.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-verify-status.md +33 -0
- package/.aiox-core/development/tasks/qa-gate.md +54 -4
- package/.aiox-core/development/tasks/validate-next-story.md +39 -2
- package/.aiox-core/framework-config.yaml +1 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/README.md +69 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js +727 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/index.js +10 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/validate.js +65 -4
- package/.aiox-core/infrastructure/scripts/generate-settings-json.js +29 -4
- package/.aiox-core/infrastructure/scripts/ide-sync/agent-parser.js +4 -0
- package/.aiox-core/infrastructure/scripts/ide-sync/index.js +67 -7
- package/.aiox-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +145 -3
- package/.aiox-core/infrastructure/scripts/repair-agent-references.js +263 -0
- package/.aiox-core/infrastructure/scripts/validate-claude-integration.js +60 -8
- package/.aiox-core/infrastructure/scripts/validate-paths.js +13 -0
- package/.aiox-core/install-manifest.yaml +134 -82
- package/.aiox-core/utils/filters/index.js +2 -1
- package/.claude/commands/AIOX/agents/aiox-master.md +21 -0
- package/.claude/commands/AIOX/agents/analyst.md +21 -0
- package/.claude/commands/AIOX/agents/architect.md +21 -0
- package/.claude/commands/AIOX/agents/data-engineer.md +21 -0
- package/.claude/commands/AIOX/agents/dev.md +21 -0
- package/.claude/commands/AIOX/agents/devops.md +21 -0
- package/.claude/commands/AIOX/agents/pm.md +21 -0
- package/.claude/commands/AIOX/agents/po.md +21 -0
- package/.claude/commands/AIOX/agents/qa.md +21 -0
- package/.claude/commands/AIOX/agents/sm.md +21 -0
- package/.claude/commands/AIOX/agents/squad-creator.md +21 -0
- package/.claude/commands/AIOX/agents/ux-design-expert.md +21 -0
- package/.claude/commands/AIOX/scripts/agent-config-loader.js +624 -0
- package/.claude/commands/AIOX/scripts/generate-greeting.js +160 -0
- package/.claude/commands/AIOX/scripts/greeting-builder.js +866 -0
- package/.claude/commands/AIOX/scripts/session-context-loader.js +286 -0
- package/.claude/commands/AIOX/stories/story-6.1.4.md +1404 -0
- package/.claude/commands/cohort-squad/agents/cohort-manager.md +156 -0
- package/.claude/commands/design-system/agents/brad-frost.md +1097 -0
- package/.claude/commands/design-system/agents/dan-mall.md +857 -0
- package/.claude/commands/design-system/agents/dave-malouf.md +2272 -0
- package/.claude/commands/design-system/agents/design-chief.md +102 -0
- package/.claude/commands/design-system/agents/nano-banana-generator.md +162 -0
- package/.claude/commands/greet.md +101 -0
- package/.claude/commands/synapse/manager.md +75 -0
- package/.claude/commands/synapse/tasks/add-rule.md +94 -0
- package/.claude/commands/synapse/tasks/create-command.md +109 -0
- package/.claude/commands/synapse/tasks/create-domain.md +127 -0
- package/.claude/commands/synapse/tasks/diagnose-synapse.md +245 -0
- package/.claude/commands/synapse/tasks/edit-rule.md +109 -0
- package/.claude/commands/synapse/tasks/suggest-domain.md +116 -0
- package/.claude/commands/synapse/tasks/toggle-domain.md +83 -0
- package/.claude/commands/synapse/templates/domain-template +8 -0
- package/.claude/commands/synapse/templates/manifest-entry-template +4 -0
- package/.claude/commands/synapse/utils/manifest-parser-reference.md +134 -0
- package/.claude/hooks/precompact-session-digest.cjs +2 -2
- package/.claude/skills/AIOX/agents/aiox-master/SKILL.md +511 -0
- package/.claude/skills/AIOX/agents/analyst/SKILL.md +281 -0
- package/.claude/skills/AIOX/agents/architect/SKILL.md +482 -0
- package/.claude/skills/AIOX/agents/data-engineer/SKILL.md +503 -0
- package/.claude/skills/AIOX/agents/dev/SKILL.md +568 -0
- package/.claude/skills/AIOX/agents/devops/SKILL.md +597 -0
- package/.claude/skills/AIOX/agents/pm/SKILL.md +385 -0
- package/.claude/skills/AIOX/agents/po/SKILL.md +343 -0
- package/.claude/skills/AIOX/agents/qa/SKILL.md +451 -0
- package/.claude/skills/AIOX/agents/sm/SKILL.md +295 -0
- package/.claude/skills/AIOX/agents/squad-creator/SKILL.md +352 -0
- package/.claude/skills/AIOX/agents/ux-design-expert/SKILL.md +503 -0
- package/.claude/skills/architect-first/SKILL.md +275 -0
- package/.claude/skills/architect-first/assets/architecture-template.md +505 -0
- package/.claude/skills/architect-first/assets/config-template.yaml +351 -0
- package/.claude/skills/architect-first/references/architecture-checklist.md +216 -0
- package/.claude/skills/architect-first/references/pre-implementation-checklist.md +119 -0
- package/.claude/skills/architect-first/references/stop-rules-guide.md +291 -0
- package/.claude/skills/architect-first/references/testing-strategy-guide.md +477 -0
- package/.claude/skills/architect-first/scripts/architecture_validator.py +490 -0
- package/.claude/skills/architect-first/scripts/check_coupling.py +306 -0
- package/.claude/skills/architect-first/scripts/validate_risk_mitigation.py +382 -0
- package/.claude/skills/checklist-runner/SKILL.md +113 -0
- package/.claude/skills/clone-mind.md +329 -0
- package/.claude/skills/coderabbit-review/SKILL.md +106 -0
- package/.claude/skills/course-generation-workflow.md +76 -0
- package/.claude/skills/enhance-workflow.md +466 -0
- package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
- package/.claude/skills/mcp-builder/SKILL.md +328 -0
- package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
- package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/.claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/.claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
- package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/.claude/skills/ralph.md +181 -0
- package/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/skill-creator/SKILL.md +209 -0
- package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/.claude/skills/squad.md +301 -0
- package/.claude/skills/synapse/SKILL.md +132 -0
- package/.claude/skills/synapse/assets/README.md +50 -0
- package/.claude/skills/synapse/references/brackets.md +100 -0
- package/.claude/skills/synapse/references/commands.md +118 -0
- package/.claude/skills/synapse/references/domains.md +126 -0
- package/.claude/skills/synapse/references/layers.md +186 -0
- package/.claude/skills/synapse/references/manifest.md +142 -0
- package/.claude/skills/tech-search/SKILL.md +431 -0
- package/.claude/skills/tech-search/prompts/page-extract.md +133 -0
- package/README.en.md +2 -2
- package/README.md +8 -2
- package/bin/aiox.js +55 -4
- package/bin/utils/framework-guard.js +4 -2
- package/bin/utils/pro-detector.js +119 -28
- package/bin/utils/validate-publish.js +6 -6
- package/docs/aiox-agent-flows/devops-system.md +18 -0
- package/docs/aiox-workflows/README.md +1 -0
- package/docs/aiox-workflows/pro-access-grant-workflow.md +218 -0
- package/docs/guides/pro/access-grant-ops-playbook.md +370 -0
- package/docs/guides/pro/install-gate-setup.md +12 -6
- package/docs/guides/pro/squad-creator-handoff-pro-access-ops.md +134 -0
- package/docs/guides/supabase-ops-handoff.md +768 -0
- package/package.json +12 -1
- package/packages/aiox-pro-cli/bin/aiox-pro.js +33 -12
- package/packages/installer/src/config/configure-environment.js +118 -50
- package/packages/installer/src/installer/aiox-core-installer.js +124 -27
- package/packages/installer/src/installer/brownfield-upgrader.js +66 -9
- package/packages/installer/src/installer/dependency-installer.js +4 -0
- package/packages/installer/src/pro/pro-scaffolder.js +5 -5
- package/packages/installer/src/updater/index.js +151 -10
- package/packages/installer/src/wizard/ide-config-generator.js +73 -7
- package/packages/installer/src/wizard/index.js +119 -31
- package/packages/installer/src/wizard/pro-setup.js +118 -47
- package/packages/installer/src/wizard/validation/validators/dependency-validator.js +32 -25
- package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +26 -0
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +84 -1
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +1 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +85 -19
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +4 -4
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +5 -5
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +4 -4
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +11 -11
- package/pro/README.md +12 -1
- package/pro/license/index.js +3 -11
- package/pro/license/license-api.js +25 -0
- package/pro/license/license-cache.js +135 -31
- package/pro/license/license-crypto.js +59 -3
- package/pro/package.json +5 -4
- package/pro/squads/README.md +16 -16
- package/pro/squads/index.js +1 -1
- package/scripts/e2e/installed-skills-smoke.js +264 -0
- package/scripts/package-synapse.js +3 -3
- package/scripts/validate-package-completeness.js +8 -11
- package/.aiox-core/lib/build.json +0 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# Testing Strategy Guide
|
|
2
|
+
|
|
3
|
+
Guide for implementing the "Quality Escape Hatch" philosophy: tests as safety net for temporary imperfection.
|
|
4
|
+
|
|
5
|
+
## Core Philosophy
|
|
6
|
+
|
|
7
|
+
**Tests permit temporary imperfection**
|
|
8
|
+
|
|
9
|
+
- Code quality is negotiable IF backed by comprehensive tests
|
|
10
|
+
- "Ugly" code WITH tests is acceptable
|
|
11
|
+
- "Ugly" code WITHOUT tests is rejected
|
|
12
|
+
- Tests are the safety net that enables pragmatic execution
|
|
13
|
+
|
|
14
|
+
## Testing Hierarchy
|
|
15
|
+
|
|
16
|
+
### 1. Unit Tests
|
|
17
|
+
|
|
18
|
+
**Purpose**: Validate individual components in isolation
|
|
19
|
+
|
|
20
|
+
**When to write**:
|
|
21
|
+
- Before or immediately after writing the component
|
|
22
|
+
- For all business logic
|
|
23
|
+
- For all data transformations
|
|
24
|
+
- For all utility functions
|
|
25
|
+
|
|
26
|
+
**Coverage targets**:
|
|
27
|
+
- Minimum 80% coverage for new code
|
|
28
|
+
- 100% coverage for critical paths
|
|
29
|
+
- All edge cases tested
|
|
30
|
+
|
|
31
|
+
**Example structure**:
|
|
32
|
+
```python
|
|
33
|
+
def test_component_happy_path():
|
|
34
|
+
"""Test the primary use case"""
|
|
35
|
+
# Arrange
|
|
36
|
+
input_data = create_test_data()
|
|
37
|
+
|
|
38
|
+
# Act
|
|
39
|
+
result = my_component(input_data)
|
|
40
|
+
|
|
41
|
+
# Assert
|
|
42
|
+
assert result.is_valid()
|
|
43
|
+
assert result.output == expected_output
|
|
44
|
+
|
|
45
|
+
def test_component_edge_case_empty_input():
|
|
46
|
+
"""Test edge case: empty input"""
|
|
47
|
+
result = my_component([])
|
|
48
|
+
assert result.is_empty()
|
|
49
|
+
|
|
50
|
+
def test_component_error_invalid_input():
|
|
51
|
+
"""Test error handling: invalid input"""
|
|
52
|
+
with pytest.raises(ValidationError):
|
|
53
|
+
my_component(invalid_data)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Integration Tests
|
|
57
|
+
|
|
58
|
+
**Purpose**: Validate component interactions and workflows
|
|
59
|
+
|
|
60
|
+
**When to write**:
|
|
61
|
+
- After multiple components are implemented
|
|
62
|
+
- For cross-module interactions
|
|
63
|
+
- For data flow validations
|
|
64
|
+
- For configuration loading
|
|
65
|
+
|
|
66
|
+
**Coverage targets**:
|
|
67
|
+
- All major workflows tested end-to-end
|
|
68
|
+
- All integration points validated
|
|
69
|
+
- Configuration variations tested
|
|
70
|
+
|
|
71
|
+
**Example structure**:
|
|
72
|
+
```python
|
|
73
|
+
def test_workflow_user_registration():
|
|
74
|
+
"""Test complete user registration workflow"""
|
|
75
|
+
# Setup
|
|
76
|
+
config = load_test_config()
|
|
77
|
+
system = SystemUnderTest(config)
|
|
78
|
+
|
|
79
|
+
# Execute workflow
|
|
80
|
+
user_data = create_test_user()
|
|
81
|
+
result = system.register_user(user_data)
|
|
82
|
+
|
|
83
|
+
# Validate workflow steps
|
|
84
|
+
assert result.validation_passed
|
|
85
|
+
assert result.user_created
|
|
86
|
+
assert result.notification_sent
|
|
87
|
+
|
|
88
|
+
# Validate integration
|
|
89
|
+
assert database.user_exists(user_data.email)
|
|
90
|
+
assert email_service.sent_welcome_email(user_data.email)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. End-to-End Tests
|
|
94
|
+
|
|
95
|
+
**Purpose**: Validate complete system behavior from user perspective
|
|
96
|
+
|
|
97
|
+
**When to write**:
|
|
98
|
+
- After core use case is implemented
|
|
99
|
+
- For acceptance criteria validation
|
|
100
|
+
- For user story validation
|
|
101
|
+
|
|
102
|
+
**Coverage targets**:
|
|
103
|
+
- All user stories have E2E test
|
|
104
|
+
- All acceptance criteria validated
|
|
105
|
+
- Core use case thoroughly tested
|
|
106
|
+
|
|
107
|
+
**Example structure**:
|
|
108
|
+
```python
|
|
109
|
+
def test_e2e_complete_user_journey():
|
|
110
|
+
"""Test complete user journey from registration to usage"""
|
|
111
|
+
# User registers
|
|
112
|
+
user = register_new_user()
|
|
113
|
+
|
|
114
|
+
# User logs in
|
|
115
|
+
session = login_user(user.credentials)
|
|
116
|
+
|
|
117
|
+
# User performs core action
|
|
118
|
+
result = perform_core_action(session)
|
|
119
|
+
|
|
120
|
+
# Validate complete journey
|
|
121
|
+
assert result.success
|
|
122
|
+
assert user_activity_logged()
|
|
123
|
+
assert metrics_updated()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Test-Driven Development (TDD) Pattern
|
|
127
|
+
|
|
128
|
+
### Standard TDD Cycle
|
|
129
|
+
|
|
130
|
+
1. **Red**: Write failing test first
|
|
131
|
+
2. **Green**: Write minimal code to pass test
|
|
132
|
+
3. **Refactor**: Improve code while keeping tests green
|
|
133
|
+
|
|
134
|
+
### Architect-First TDD Adaptation
|
|
135
|
+
|
|
136
|
+
1. **Architect**: Design and document first
|
|
137
|
+
2. **Red**: Write tests based on architecture
|
|
138
|
+
3. **Green**: Implement to pass tests (code can be "ugly")
|
|
139
|
+
4. **Refactor**: Improve code quality (optional, tests enable this)
|
|
140
|
+
|
|
141
|
+
**Key difference**: Architecture and documentation precede test writing.
|
|
142
|
+
|
|
143
|
+
## Quality Escape Hatch: When "Ugly" Code is Acceptable
|
|
144
|
+
|
|
145
|
+
### Conditions for Acceptance
|
|
146
|
+
|
|
147
|
+
"Ugly" code is acceptable when ALL of these are true:
|
|
148
|
+
|
|
149
|
+
1. ✅ **Comprehensive tests exist**
|
|
150
|
+
- Unit tests cover all logic paths
|
|
151
|
+
- Integration tests validate workflows
|
|
152
|
+
- Tests actually run and pass
|
|
153
|
+
|
|
154
|
+
2. ✅ **Logging/observation points added**
|
|
155
|
+
- Key decision points logged
|
|
156
|
+
- Error context captured
|
|
157
|
+
- Debugging hooks available
|
|
158
|
+
|
|
159
|
+
3. ✅ **Core use case works**
|
|
160
|
+
- Primary workflow functional
|
|
161
|
+
- Acceptance criteria met
|
|
162
|
+
- User value delivered
|
|
163
|
+
|
|
164
|
+
4. ✅ **Technical debt documented**
|
|
165
|
+
- TODO comments with context
|
|
166
|
+
- Refactoring plan outlined
|
|
167
|
+
- Known limitations documented
|
|
168
|
+
|
|
169
|
+
### Examples of Acceptable "Ugly" Code
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# ACCEPTABLE: Nested ifs, but fully tested
|
|
173
|
+
def process_data(data):
|
|
174
|
+
"""Process data through validation pipeline.
|
|
175
|
+
|
|
176
|
+
TODO: Refactor nested ifs to strategy pattern
|
|
177
|
+
See: docs/refactoring/data-processing.md
|
|
178
|
+
"""
|
|
179
|
+
if data.type == "A":
|
|
180
|
+
if data.valid:
|
|
181
|
+
if data.priority == "high":
|
|
182
|
+
return fast_process_a(data)
|
|
183
|
+
else:
|
|
184
|
+
return slow_process_a(data)
|
|
185
|
+
else:
|
|
186
|
+
raise ValidationError("Invalid A")
|
|
187
|
+
elif data.type == "B":
|
|
188
|
+
# Similar nesting...
|
|
189
|
+
pass
|
|
190
|
+
# ... comprehensive tests exist for all paths
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
# ACCEPTABLE: Quick implementation, but tested
|
|
195
|
+
def calculate_metrics(records):
|
|
196
|
+
"""Calculate metrics from records.
|
|
197
|
+
|
|
198
|
+
TODO: Optimize query - currently loads all to memory
|
|
199
|
+
Performance: ~500ms for 10k records (acceptable for MVP)
|
|
200
|
+
"""
|
|
201
|
+
# Load everything (inefficient but works)
|
|
202
|
+
all_data = list(records)
|
|
203
|
+
|
|
204
|
+
# Calculate (could be vectorized)
|
|
205
|
+
result = sum(r.value for r in all_data) / len(all_data)
|
|
206
|
+
|
|
207
|
+
logging.info(f"Calculated metric: {result} from {len(all_data)} records")
|
|
208
|
+
return result
|
|
209
|
+
# Unit tests verify correctness
|
|
210
|
+
# Integration tests verify performance acceptable
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Examples of UNACCEPTABLE Code
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
# REJECTED: No tests, no logging
|
|
217
|
+
def process_important_data(data):
|
|
218
|
+
# Complex logic with no tests
|
|
219
|
+
result = data.field1 + data.field2 * 3.14
|
|
220
|
+
if result > threshold: # hardcoded threshold
|
|
221
|
+
return do_something(result)
|
|
222
|
+
return None
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
# REJECTED: Tests exist but don't actually validate behavior
|
|
227
|
+
def calculate_revenue(orders):
|
|
228
|
+
# Complex calculation
|
|
229
|
+
total = sum(o.amount for o in orders)
|
|
230
|
+
return total * 1.1 # Why 1.1? No comment, no doc
|
|
231
|
+
|
|
232
|
+
def test_calculate_revenue():
|
|
233
|
+
# Useless test - doesn't validate logic
|
|
234
|
+
result = calculate_revenue([])
|
|
235
|
+
assert result >= 0 # Always passes, validates nothing
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Logging Strategy for Test Support
|
|
239
|
+
|
|
240
|
+
### Strategic Logging Points
|
|
241
|
+
|
|
242
|
+
1. **Entry/Exit of major functions**
|
|
243
|
+
```python
|
|
244
|
+
logging.info(f"Starting process_workflow with {len(items)} items")
|
|
245
|
+
result = process_workflow(items)
|
|
246
|
+
logging.info(f"Completed process_workflow: {result.summary()}")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
2. **Decision points**
|
|
250
|
+
```python
|
|
251
|
+
if should_use_fast_path(data):
|
|
252
|
+
logging.debug("Using fast path: criteria met")
|
|
253
|
+
return fast_path(data)
|
|
254
|
+
else:
|
|
255
|
+
logging.debug(f"Using slow path: {data.reason}")
|
|
256
|
+
return slow_path(data)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
3. **Error conditions**
|
|
260
|
+
```python
|
|
261
|
+
try:
|
|
262
|
+
result = risky_operation()
|
|
263
|
+
except ValidationError as e:
|
|
264
|
+
logging.error(f"Validation failed: {e}", extra={
|
|
265
|
+
"input": data,
|
|
266
|
+
"context": current_context
|
|
267
|
+
})
|
|
268
|
+
raise
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
4. **Performance monitoring**
|
|
272
|
+
```python
|
|
273
|
+
import time
|
|
274
|
+
start = time.time()
|
|
275
|
+
result = expensive_operation()
|
|
276
|
+
duration = time.time() - start
|
|
277
|
+
logging.info(f"Operation completed in {duration:.2f}s")
|
|
278
|
+
if duration > THRESHOLD:
|
|
279
|
+
logging.warning(f"Operation slow: {duration:.2f}s > {THRESHOLD}s")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Test Organization
|
|
283
|
+
|
|
284
|
+
### Directory Structure
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
project/
|
|
288
|
+
├── src/
|
|
289
|
+
│ └── module/
|
|
290
|
+
│ ├── __init__.py
|
|
291
|
+
│ └── component.py
|
|
292
|
+
├── tests/
|
|
293
|
+
│ ├── unit/
|
|
294
|
+
│ │ └── test_component.py
|
|
295
|
+
│ ├── integration/
|
|
296
|
+
│ │ └── test_module_integration.py
|
|
297
|
+
│ └── e2e/
|
|
298
|
+
│ └── test_user_workflows.py
|
|
299
|
+
└── conftest.py # Shared fixtures
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Naming Conventions
|
|
303
|
+
|
|
304
|
+
- Test files: `test_*.py`
|
|
305
|
+
- Test functions: `test_[component]_[scenario]`
|
|
306
|
+
- Test classes: `Test[Component]`
|
|
307
|
+
|
|
308
|
+
**Examples**:
|
|
309
|
+
- `test_parser_valid_input()`
|
|
310
|
+
- `test_parser_empty_input()`
|
|
311
|
+
- `test_parser_invalid_format_raises_error()`
|
|
312
|
+
|
|
313
|
+
## Test Fixtures and Helpers
|
|
314
|
+
|
|
315
|
+
### Configuration for Tests
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
# conftest.py
|
|
319
|
+
import pytest
|
|
320
|
+
|
|
321
|
+
@pytest.fixture
|
|
322
|
+
def test_config():
|
|
323
|
+
"""Load test configuration"""
|
|
324
|
+
return {
|
|
325
|
+
"database": "sqlite:///:memory:",
|
|
326
|
+
"log_level": "DEBUG",
|
|
327
|
+
"timeout": 1.0
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
@pytest.fixture
|
|
331
|
+
def sample_data():
|
|
332
|
+
"""Create sample test data"""
|
|
333
|
+
return [
|
|
334
|
+
{"id": 1, "value": 100},
|
|
335
|
+
{"id": 2, "value": 200},
|
|
336
|
+
]
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Mock External Dependencies
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
from unittest.mock import Mock, patch
|
|
343
|
+
|
|
344
|
+
def test_with_external_api():
|
|
345
|
+
"""Test component that calls external API"""
|
|
346
|
+
with patch('module.external_api') as mock_api:
|
|
347
|
+
mock_api.fetch_data.return_value = {"status": "ok"}
|
|
348
|
+
|
|
349
|
+
result = my_component.process()
|
|
350
|
+
|
|
351
|
+
assert result.success
|
|
352
|
+
mock_api.fetch_data.assert_called_once()
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Running Tests
|
|
356
|
+
|
|
357
|
+
### Local Development
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# Run all tests
|
|
361
|
+
pytest
|
|
362
|
+
|
|
363
|
+
# Run with coverage
|
|
364
|
+
pytest --cov=src --cov-report=html
|
|
365
|
+
|
|
366
|
+
# Run specific test file
|
|
367
|
+
pytest tests/unit/test_component.py
|
|
368
|
+
|
|
369
|
+
# Run specific test
|
|
370
|
+
pytest tests/unit/test_component.py::test_parser_valid_input
|
|
371
|
+
|
|
372
|
+
# Run with verbose output
|
|
373
|
+
pytest -v
|
|
374
|
+
|
|
375
|
+
# Run with logging output
|
|
376
|
+
pytest -s --log-cli-level=DEBUG
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### CI/CD Integration
|
|
380
|
+
|
|
381
|
+
```yaml
|
|
382
|
+
# .github/workflows/test.yml
|
|
383
|
+
name: Tests
|
|
384
|
+
|
|
385
|
+
on: [push, pull_request]
|
|
386
|
+
|
|
387
|
+
jobs:
|
|
388
|
+
test:
|
|
389
|
+
runs-on: ubuntu-latest
|
|
390
|
+
steps:
|
|
391
|
+
- uses: actions/checkout@v2
|
|
392
|
+
- name: Set up Python
|
|
393
|
+
uses: actions/setup-python@v2
|
|
394
|
+
with:
|
|
395
|
+
python-version: 3.9
|
|
396
|
+
- name: Install dependencies
|
|
397
|
+
run: pip install -r requirements-test.txt
|
|
398
|
+
- name: Run tests
|
|
399
|
+
run: pytest --cov=src --cov-fail-under=80
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Coverage Targets
|
|
403
|
+
|
|
404
|
+
### Minimum Coverage Requirements
|
|
405
|
+
|
|
406
|
+
- **New code**: 80% minimum
|
|
407
|
+
- **Critical paths**: 100% required
|
|
408
|
+
- **Existing code**: No decrease allowed
|
|
409
|
+
|
|
410
|
+
### Measuring Coverage
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Generate coverage report
|
|
414
|
+
pytest --cov=src --cov-report=html
|
|
415
|
+
|
|
416
|
+
# View in browser
|
|
417
|
+
open htmlcov/index.html
|
|
418
|
+
|
|
419
|
+
# Check specific module
|
|
420
|
+
pytest --cov=src.module --cov-report=term-missing
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Exceptions to Coverage
|
|
424
|
+
|
|
425
|
+
Acceptable to exclude from coverage:
|
|
426
|
+
- Logging statements
|
|
427
|
+
- Debug code
|
|
428
|
+
- Type checking code (`if TYPE_CHECKING:`)
|
|
429
|
+
- Abstract base class definitions
|
|
430
|
+
- Explicit `# pragma: no cover` with justification
|
|
431
|
+
|
|
432
|
+
## Test Quality Checklist
|
|
433
|
+
|
|
434
|
+
- [ ] Tests are independent (can run in any order)
|
|
435
|
+
- [ ] Tests are repeatable (same result every time)
|
|
436
|
+
- [ ] Tests are fast (< 1s for unit tests)
|
|
437
|
+
- [ ] Tests have clear names describing what they test
|
|
438
|
+
- [ ] Tests follow Arrange-Act-Assert pattern
|
|
439
|
+
- [ ] Edge cases are tested
|
|
440
|
+
- [ ] Error conditions are tested
|
|
441
|
+
- [ ] Tests don't depend on external state
|
|
442
|
+
- [ ] Mocks are used for external dependencies
|
|
443
|
+
- [ ] Test data is clearly defined
|
|
444
|
+
|
|
445
|
+
## Refactoring with Test Safety Net
|
|
446
|
+
|
|
447
|
+
**Process**:
|
|
448
|
+
|
|
449
|
+
1. Ensure comprehensive tests exist
|
|
450
|
+
2. Run tests → all green
|
|
451
|
+
3. Refactor code incrementally
|
|
452
|
+
4. Run tests after each change
|
|
453
|
+
5. If tests fail → fix or revert
|
|
454
|
+
6. Continue refactoring
|
|
455
|
+
7. Final test run → all green
|
|
456
|
+
8. Commit
|
|
457
|
+
|
|
458
|
+
**Rules**:
|
|
459
|
+
- NEVER refactor without tests
|
|
460
|
+
- NEVER change tests and code simultaneously
|
|
461
|
+
- ALWAYS keep tests passing
|
|
462
|
+
- COMMIT frequently with passing tests
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## Summary
|
|
467
|
+
|
|
468
|
+
**Quality Escape Hatch in Practice**:
|
|
469
|
+
|
|
470
|
+
1. **Before coding**: Define test plan
|
|
471
|
+
2. **While coding**: Write tests (can be concurrent or after)
|
|
472
|
+
3. **Code quality**: Can be "ugly" IF tests comprehensive
|
|
473
|
+
4. **Validation**: Tests + logs + manual inspection
|
|
474
|
+
5. **Refactoring**: Optional, enabled by tests
|
|
475
|
+
6. **Deployment**: Core case working + tests passing
|
|
476
|
+
|
|
477
|
+
**Remember**: Tests are your license to write imperfect code. Without tests, perfection is required.
|