agentic-qe 2.0.0 → 2.1.1
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/.claude/agents/qx-partner.md +17 -4
- package/.claude/skills/accessibility-testing/SKILL.md +144 -692
- package/.claude/skills/agentic-quality-engineering/SKILL.md +176 -529
- package/.claude/skills/api-testing-patterns/SKILL.md +180 -560
- package/.claude/skills/brutal-honesty-review/SKILL.md +113 -603
- package/.claude/skills/bug-reporting-excellence/SKILL.md +116 -517
- package/.claude/skills/chaos-engineering-resilience/SKILL.md +127 -72
- package/.claude/skills/cicd-pipeline-qe-orchestrator/SKILL.md +209 -404
- package/.claude/skills/code-review-quality/SKILL.md +158 -608
- package/.claude/skills/compatibility-testing/SKILL.md +148 -38
- package/.claude/skills/compliance-testing/SKILL.md +132 -63
- package/.claude/skills/consultancy-practices/SKILL.md +114 -446
- package/.claude/skills/context-driven-testing/SKILL.md +117 -381
- package/.claude/skills/contract-testing/SKILL.md +176 -141
- package/.claude/skills/database-testing/SKILL.md +137 -130
- package/.claude/skills/exploratory-testing-advanced/SKILL.md +160 -629
- package/.claude/skills/holistic-testing-pact/SKILL.md +140 -188
- package/.claude/skills/localization-testing/SKILL.md +145 -33
- package/.claude/skills/mobile-testing/SKILL.md +132 -448
- package/.claude/skills/mutation-testing/SKILL.md +147 -41
- package/.claude/skills/performance-testing/SKILL.md +200 -546
- package/.claude/skills/quality-metrics/SKILL.md +164 -519
- package/.claude/skills/refactoring-patterns/SKILL.md +132 -699
- package/.claude/skills/regression-testing/SKILL.md +120 -926
- package/.claude/skills/risk-based-testing/SKILL.md +157 -660
- package/.claude/skills/security-testing/SKILL.md +199 -538
- package/.claude/skills/sherlock-review/SKILL.md +163 -699
- package/.claude/skills/shift-left-testing/SKILL.md +161 -465
- package/.claude/skills/shift-right-testing/SKILL.md +161 -519
- package/.claude/skills/six-thinking-hats/SKILL.md +175 -1110
- package/.claude/skills/skills-manifest.json +71 -20
- package/.claude/skills/tdd-london-chicago/SKILL.md +131 -448
- package/.claude/skills/technical-writing/SKILL.md +103 -154
- package/.claude/skills/test-automation-strategy/SKILL.md +166 -772
- package/.claude/skills/test-data-management/SKILL.md +126 -910
- package/.claude/skills/test-design-techniques/SKILL.md +179 -89
- package/.claude/skills/test-environment-management/SKILL.md +136 -91
- package/.claude/skills/test-reporting-analytics/SKILL.md +169 -92
- package/.claude/skills/testability-scoring/SKILL.md +172 -538
- package/.claude/skills/testability-scoring/scripts/generate-html-report.js +0 -0
- package/.claude/skills/visual-testing-advanced/SKILL.md +155 -78
- package/.claude/skills/xp-practices/SKILL.md +151 -587
- package/CHANGELOG.md +86 -0
- package/README.md +23 -16
- package/dist/agents/QXPartnerAgent.d.ts +47 -1
- package/dist/agents/QXPartnerAgent.d.ts.map +1 -1
- package/dist/agents/QXPartnerAgent.js +2086 -125
- package/dist/agents/QXPartnerAgent.js.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.d.ts.map +1 -1
- package/dist/agents/lifecycle/AgentLifecycleManager.js +34 -31
- package/dist/agents/lifecycle/AgentLifecycleManager.js.map +1 -1
- package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
- package/dist/cli/commands/init-claude-md-template.js +14 -0
- package/dist/cli/commands/init-claude-md-template.js.map +1 -1
- package/dist/core/SwarmCoordinator.d.ts +180 -0
- package/dist/core/SwarmCoordinator.d.ts.map +1 -0
- package/dist/core/SwarmCoordinator.js +473 -0
- package/dist/core/SwarmCoordinator.js.map +1 -0
- package/dist/core/memory/ReflexionMemoryAdapter.d.ts +109 -0
- package/dist/core/memory/ReflexionMemoryAdapter.d.ts.map +1 -0
- package/dist/core/memory/ReflexionMemoryAdapter.js +306 -0
- package/dist/core/memory/ReflexionMemoryAdapter.js.map +1 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts +28 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts.map +1 -1
- package/dist/core/memory/RuVectorPatternStore.js +70 -0
- package/dist/core/memory/RuVectorPatternStore.js.map +1 -1
- package/dist/core/memory/SparseVectorSearch.d.ts +55 -0
- package/dist/core/memory/SparseVectorSearch.d.ts.map +1 -0
- package/dist/core/memory/SparseVectorSearch.js +130 -0
- package/dist/core/memory/SparseVectorSearch.js.map +1 -0
- package/dist/core/memory/TieredCompression.d.ts +81 -0
- package/dist/core/memory/TieredCompression.d.ts.map +1 -0
- package/dist/core/memory/TieredCompression.js +270 -0
- package/dist/core/memory/TieredCompression.js.map +1 -0
- package/dist/core/memory/index.d.ts +6 -0
- package/dist/core/memory/index.d.ts.map +1 -1
- package/dist/core/memory/index.js +29 -1
- package/dist/core/memory/index.js.map +1 -1
- package/dist/core/metrics/MetricsAggregator.d.ts +228 -0
- package/dist/core/metrics/MetricsAggregator.d.ts.map +1 -0
- package/dist/core/metrics/MetricsAggregator.js +482 -0
- package/dist/core/metrics/MetricsAggregator.js.map +1 -0
- package/dist/core/metrics/index.d.ts +5 -0
- package/dist/core/metrics/index.d.ts.map +1 -0
- package/dist/core/metrics/index.js +11 -0
- package/dist/core/metrics/index.js.map +1 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts +5 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -1
- package/dist/core/optimization/SwarmOptimizer.js +17 -0
- package/dist/core/optimization/SwarmOptimizer.js.map +1 -1
- package/dist/core/orchestration/AdaptiveScheduler.d.ts +190 -0
- package/dist/core/orchestration/AdaptiveScheduler.d.ts.map +1 -0
- package/dist/core/orchestration/AdaptiveScheduler.js +460 -0
- package/dist/core/orchestration/AdaptiveScheduler.js.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts +13 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -1
- package/dist/core/orchestration/WorkflowOrchestrator.js +32 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -1
- package/dist/core/recovery/CircuitBreaker.d.ts +176 -0
- package/dist/core/recovery/CircuitBreaker.d.ts.map +1 -0
- package/dist/core/recovery/CircuitBreaker.js +382 -0
- package/dist/core/recovery/CircuitBreaker.js.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts +186 -0
- package/dist/core/recovery/RecoveryOrchestrator.d.ts.map +1 -0
- package/dist/core/recovery/RecoveryOrchestrator.js +476 -0
- package/dist/core/recovery/RecoveryOrchestrator.js.map +1 -0
- package/dist/core/recovery/RetryStrategy.d.ts +127 -0
- package/dist/core/recovery/RetryStrategy.d.ts.map +1 -0
- package/dist/core/recovery/RetryStrategy.js +314 -0
- package/dist/core/recovery/RetryStrategy.js.map +1 -0
- package/dist/core/recovery/index.d.ts +8 -0
- package/dist/core/recovery/index.d.ts.map +1 -0
- package/dist/core/recovery/index.js +27 -0
- package/dist/core/recovery/index.js.map +1 -0
- package/dist/core/skills/DependencyResolver.d.ts +99 -0
- package/dist/core/skills/DependencyResolver.d.ts.map +1 -0
- package/dist/core/skills/DependencyResolver.js +260 -0
- package/dist/core/skills/DependencyResolver.js.map +1 -0
- package/dist/core/skills/ManifestGenerator.d.ts +114 -0
- package/dist/core/skills/ManifestGenerator.d.ts.map +1 -0
- package/dist/core/skills/ManifestGenerator.js +449 -0
- package/dist/core/skills/ManifestGenerator.js.map +1 -0
- package/dist/core/skills/index.d.ts +9 -0
- package/dist/core/skills/index.d.ts.map +1 -0
- package/dist/core/skills/index.js +24 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/mcp/handlers/chaos/chaos-inject-failure.d.ts +5 -0
- package/dist/mcp/handlers/chaos/chaos-inject-failure.d.ts.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-failure.js +36 -2
- package/dist/mcp/handlers/chaos/chaos-inject-failure.js.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-latency.d.ts +5 -0
- package/dist/mcp/handlers/chaos/chaos-inject-latency.d.ts.map +1 -1
- package/dist/mcp/handlers/chaos/chaos-inject-latency.js +36 -2
- package/dist/mcp/handlers/chaos/chaos-inject-latency.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -9
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +1 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/types/qx.d.ts +113 -7
- package/dist/types/qx.d.ts.map +1 -1
- package/dist/types/qx.js.map +1 -1
- package/dist/visualization/api/RestEndpoints.js +1 -1
- package/dist/visualization/api/RestEndpoints.js.map +1 -1
- package/package.json +15 -54
|
@@ -1,251 +1,73 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test-data-management
|
|
3
|
-
description: Strategic test data generation, management, and privacy compliance. Use when creating test data, handling PII, ensuring GDPR/CCPA compliance, or scaling data generation for realistic testing scenarios.
|
|
3
|
+
description: "Strategic test data generation, management, and privacy compliance. Use when creating test data, handling PII, ensuring GDPR/CCPA compliance, or scaling data generation for realistic testing scenarios."
|
|
4
|
+
category: specialized-testing
|
|
5
|
+
priority: high
|
|
6
|
+
tokenEstimate: 1000
|
|
7
|
+
agents: [qe-test-data-architect, qe-test-executor, qe-security-scanner]
|
|
8
|
+
implementation_status: optimized
|
|
9
|
+
optimization_version: 1.0
|
|
10
|
+
last_optimized: 2025-12-02
|
|
11
|
+
dependencies: []
|
|
12
|
+
quick_reference_card: true
|
|
13
|
+
tags: [test-data, faker, synthetic, gdpr, pii, anonymization, factories]
|
|
4
14
|
---
|
|
5
15
|
|
|
6
16
|
# Test Data Management
|
|
7
17
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
##
|
|
28
|
-
|
|
29
|
-
###
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Realistic Data (Production-Like)**
|
|
53
|
-
```javascript
|
|
54
|
-
// Production-like complexity
|
|
55
|
-
const user = {
|
|
56
|
-
id: '7f3a9c2e-4b1d-4e8a-9f2c-6d5e8a1b3c4d',
|
|
57
|
-
email: 'sarah.johnson@techcorp.com',
|
|
58
|
-
firstName: 'Sarah',
|
|
59
|
-
lastName: 'Johnson',
|
|
60
|
-
phone: '+1-555-0123',
|
|
61
|
-
address: {
|
|
62
|
-
street: '742 Evergreen Terrace',
|
|
63
|
-
city: 'Springfield',
|
|
64
|
-
state: 'IL',
|
|
65
|
-
zip: '62701',
|
|
66
|
-
country: 'US'
|
|
67
|
-
},
|
|
68
|
-
preferences: {
|
|
69
|
-
newsletter: true,
|
|
70
|
-
language: 'en-US',
|
|
71
|
-
timezone: 'America/Chicago'
|
|
72
|
-
},
|
|
73
|
-
createdAt: '2025-01-15T10:30:00Z',
|
|
74
|
-
lastLogin: '2025-10-24T14:22:15Z'
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Benefits:
|
|
78
|
-
// - Catches edge cases
|
|
79
|
-
// - Tests real-world scenarios
|
|
80
|
-
// - Validates integrations
|
|
81
|
-
// - Performance realistic
|
|
82
|
-
|
|
83
|
-
// Use when:
|
|
84
|
-
// - Integration tests
|
|
85
|
-
// - E2E tests
|
|
86
|
-
// - Performance tests
|
|
87
|
-
// - Production validation
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Hybrid Approach (Best Practice)**
|
|
91
|
-
```javascript
|
|
92
|
-
// Minimal for fast tests, realistic for critical paths
|
|
93
|
-
describe('User Service', () => {
|
|
94
|
-
// Unit test: minimal data
|
|
95
|
-
test('validates email format', () => {
|
|
96
|
-
expect(validateEmail('test@example.com')).toBe(true);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Integration test: realistic data
|
|
100
|
-
test('creates user with full profile', async () => {
|
|
101
|
-
const user = generateRealisticUser(); // Full data
|
|
102
|
-
const result = await userService.create(user);
|
|
103
|
-
expect(result.profile.address.country).toBe('US');
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
### Strategy 2: Shared vs Isolated Data
|
|
111
|
-
|
|
112
|
-
**Shared Data (Read-Only)**
|
|
113
|
-
```javascript
|
|
114
|
-
// Seed database once, many tests use it
|
|
115
|
-
beforeAll(async () => {
|
|
116
|
-
await db.seed({
|
|
117
|
-
users: [
|
|
118
|
-
{ id: 1, email: 'admin@example.com', role: 'admin' },
|
|
119
|
-
{ id: 2, email: 'user@example.com', role: 'customer' }
|
|
120
|
-
],
|
|
121
|
-
products: [
|
|
122
|
-
{ id: 1, name: 'Widget', price: 9.99 },
|
|
123
|
-
{ id: 2, name: 'Gadget', price: 19.99 }
|
|
124
|
-
]
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Tests can read but not modify
|
|
129
|
-
test('admin can list all products', async () => {
|
|
130
|
-
const admin = await db.users.find({ id: 1 });
|
|
131
|
-
const products = await productService.list(admin);
|
|
132
|
-
expect(products.length).toBeGreaterThan(0);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Benefits:
|
|
136
|
-
// - Fast (no setup per test)
|
|
137
|
-
// - Can run tests in parallel
|
|
138
|
-
// - Low resource usage
|
|
139
|
-
|
|
140
|
-
// Risks:
|
|
141
|
-
// - Tests must not modify data
|
|
142
|
-
// - Harder to debug (shared state)
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**Isolated Data (Per-Test)**
|
|
146
|
-
```javascript
|
|
147
|
-
// Each test gets its own data
|
|
148
|
-
test('user can update profile', async () => {
|
|
149
|
-
// Generate unique data for this test
|
|
150
|
-
const user = await createTestUser({
|
|
151
|
-
email: `test-${Date.now()}@example.com`
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
await userService.updateProfile(user.id, { firstName: 'Updated' });
|
|
155
|
-
|
|
156
|
-
const updated = await db.users.find({ id: user.id });
|
|
157
|
-
expect(updated.firstName).toBe('Updated');
|
|
158
|
-
|
|
159
|
-
// Cleanup
|
|
160
|
-
await db.users.delete({ id: user.id });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Benefits:
|
|
164
|
-
// - Tests independent
|
|
165
|
-
// - Can modify data freely
|
|
166
|
-
// - Easy to debug
|
|
167
|
-
// - No test pollution
|
|
168
|
-
|
|
169
|
-
// Costs:
|
|
170
|
-
// - Slower (setup per test)
|
|
171
|
-
// - More resource usage
|
|
172
|
-
// - Cleanup needed
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
**Database Transactions (Best of Both)**
|
|
176
|
-
```javascript
|
|
177
|
-
// Use transactions for isolation without cleanup
|
|
178
|
-
beforeEach(async () => {
|
|
179
|
-
await db.beginTransaction();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
afterEach(async () => {
|
|
183
|
-
await db.rollbackTransaction(); // Auto cleanup!
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
test('user registration', async () => {
|
|
187
|
-
// Data exists only in this transaction
|
|
188
|
-
const user = await userService.register({
|
|
189
|
-
email: 'test@example.com'
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
expect(user.id).toBeDefined();
|
|
193
|
-
// Automatic rollback after test
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Benefits:
|
|
197
|
-
// - Isolated (transaction boundary)
|
|
198
|
-
// - Fast (no manual cleanup)
|
|
199
|
-
// - Reliable (guaranteed cleanup)
|
|
200
|
-
```
|
|
18
|
+
<default_to_action>
|
|
19
|
+
When creating or managing test data:
|
|
20
|
+
1. NEVER use production PII directly
|
|
21
|
+
2. GENERATE synthetic data with faker libraries
|
|
22
|
+
3. ANONYMIZE production data if used (mask, hash)
|
|
23
|
+
4. ISOLATE test data (transactions, per-test cleanup)
|
|
24
|
+
5. SCALE with batch generation (10k+ records/sec)
|
|
25
|
+
|
|
26
|
+
**Quick Data Strategy:**
|
|
27
|
+
- Unit tests: Minimal data (just enough)
|
|
28
|
+
- Integration: Realistic data (full complexity)
|
|
29
|
+
- Performance: Volume data (10k+ records)
|
|
30
|
+
|
|
31
|
+
**Critical Success Factors:**
|
|
32
|
+
- 40% of test failures from inadequate data
|
|
33
|
+
- GDPR fines up to €20M for PII violations
|
|
34
|
+
- Never store production PII in test environments
|
|
35
|
+
</default_to_action>
|
|
36
|
+
|
|
37
|
+
## Quick Reference Card
|
|
38
|
+
|
|
39
|
+
### When to Use
|
|
40
|
+
- Creating test datasets
|
|
41
|
+
- Handling sensitive data
|
|
42
|
+
- Performance testing with volume
|
|
43
|
+
- GDPR/CCPA compliance
|
|
44
|
+
|
|
45
|
+
### Data Strategies
|
|
46
|
+
| Type | When | Size |
|
|
47
|
+
|------|------|------|
|
|
48
|
+
| **Minimal** | Unit tests | 1-10 records |
|
|
49
|
+
| **Realistic** | Integration | 100-1000 records |
|
|
50
|
+
| **Volume** | Performance | 10k+ records |
|
|
51
|
+
| **Edge cases** | Boundary testing | Targeted |
|
|
52
|
+
|
|
53
|
+
### Privacy Techniques
|
|
54
|
+
| Technique | Use Case |
|
|
55
|
+
|-----------|----------|
|
|
56
|
+
| **Synthetic** | Generate fake data (preferred) |
|
|
57
|
+
| **Masking** | j***@example.com |
|
|
58
|
+
| **Hashing** | Irreversible pseudonymization |
|
|
59
|
+
| **Tokenization** | Reversible with key |
|
|
201
60
|
|
|
202
61
|
---
|
|
203
62
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
**❌ Production Data (DANGER!)**
|
|
207
|
-
```javascript
|
|
208
|
-
// NEVER do this:
|
|
209
|
-
const prodDb = connectTo('production://...');
|
|
210
|
-
const users = await prodDb.users.findAll(); // ⚠️ PII exposure!
|
|
211
|
-
|
|
212
|
-
// Problems:
|
|
213
|
-
// - Contains real PII (GDPR/CCPA violation)
|
|
214
|
-
// - Can modify production data accidentally
|
|
215
|
-
// - Performance impact on prod
|
|
216
|
-
// - Security risk
|
|
217
|
-
// - Legal liability
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
**✅ Anonymized Production Data**
|
|
221
|
-
```javascript
|
|
222
|
-
// Mask/anonymize production data
|
|
223
|
-
const anonymizedUsers = prodUsers.map(user => ({
|
|
224
|
-
id: user.id, // Keep ID for relationships
|
|
225
|
-
email: `user-${user.id}@example.com`, // Fake email
|
|
226
|
-
firstName: faker.name.firstName(), // Generated name
|
|
227
|
-
lastName: faker.name.lastName(),
|
|
228
|
-
phone: null, // Remove PII
|
|
229
|
-
address: {
|
|
230
|
-
city: user.address.city, // Keep non-PII
|
|
231
|
-
state: user.address.state,
|
|
232
|
-
zip: user.address.zip.substring(0, 3) + 'XX', // Partial zip
|
|
233
|
-
street: '***REDACTED***'
|
|
234
|
-
},
|
|
235
|
-
createdAt: user.createdAt // Keep timestamps
|
|
236
|
-
}));
|
|
237
|
-
|
|
238
|
-
// Benefits:
|
|
239
|
-
// - Realistic data patterns
|
|
240
|
-
// - Compliant with privacy laws
|
|
241
|
-
// - Safe for testing
|
|
242
|
-
```
|
|
63
|
+
## Synthetic Data Generation
|
|
243
64
|
|
|
244
|
-
**✅ Synthetic Data (Best Practice)**
|
|
245
65
|
```javascript
|
|
246
66
|
import { faker } from '@faker-js/faker';
|
|
247
67
|
|
|
248
|
-
//
|
|
68
|
+
// Seed for reproducibility
|
|
69
|
+
faker.seed(123);
|
|
70
|
+
|
|
249
71
|
function generateUser() {
|
|
250
72
|
return {
|
|
251
73
|
id: faker.string.uuid(),
|
|
@@ -256,132 +78,24 @@ function generateUser() {
|
|
|
256
78
|
address: {
|
|
257
79
|
street: faker.location.streetAddress(),
|
|
258
80
|
city: faker.location.city(),
|
|
259
|
-
|
|
260
|
-
zip: faker.location.zipCode(),
|
|
261
|
-
country: 'US'
|
|
81
|
+
zip: faker.location.zipCode()
|
|
262
82
|
},
|
|
263
|
-
age: faker.number.int({ min: 18, max: 90 }),
|
|
264
83
|
createdAt: faker.date.past()
|
|
265
84
|
};
|
|
266
85
|
}
|
|
267
86
|
|
|
268
|
-
// Benefits:
|
|
269
|
-
// - No PII (privacy compliant)
|
|
270
|
-
// - Unlimited volume
|
|
271
|
-
// - Controlled characteristics
|
|
272
|
-
// - Repeatable with seeds
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
## Data Generation Techniques
|
|
278
|
-
|
|
279
|
-
### Technique 1: Faker Libraries
|
|
280
|
-
|
|
281
|
-
**Basic Usage**
|
|
282
|
-
```javascript
|
|
283
|
-
import { faker } from '@faker-js/faker';
|
|
284
|
-
|
|
285
|
-
// Seed for reproducibility
|
|
286
|
-
faker.seed(123);
|
|
287
|
-
|
|
288
|
-
// Generate various data types
|
|
289
|
-
const testData = {
|
|
290
|
-
// Personal
|
|
291
|
-
name: faker.person.fullName(),
|
|
292
|
-
email: faker.internet.email(),
|
|
293
|
-
avatar: faker.image.avatar(),
|
|
294
|
-
bio: faker.person.bio(),
|
|
295
|
-
|
|
296
|
-
// Location
|
|
297
|
-
address: faker.location.streetAddress(),
|
|
298
|
-
city: faker.location.city(),
|
|
299
|
-
country: faker.location.country(),
|
|
300
|
-
coordinates: faker.location.nearbyGPSCoordinate(),
|
|
301
|
-
|
|
302
|
-
// Financial
|
|
303
|
-
accountNumber: faker.finance.accountNumber(),
|
|
304
|
-
amount: faker.finance.amount(),
|
|
305
|
-
currency: faker.finance.currencyCode(),
|
|
306
|
-
iban: faker.finance.iban(),
|
|
307
|
-
|
|
308
|
-
// Commerce
|
|
309
|
-
product: faker.commerce.productName(),
|
|
310
|
-
price: faker.commerce.price(),
|
|
311
|
-
department: faker.commerce.department(),
|
|
312
|
-
|
|
313
|
-
// Internet
|
|
314
|
-
username: faker.internet.userName(),
|
|
315
|
-
password: faker.internet.password(),
|
|
316
|
-
url: faker.internet.url(),
|
|
317
|
-
ipv4: faker.internet.ipv4(),
|
|
318
|
-
|
|
319
|
-
// Date/Time
|
|
320
|
-
pastDate: faker.date.past(),
|
|
321
|
-
futureDate: faker.date.future(),
|
|
322
|
-
recentDate: faker.date.recent(),
|
|
323
|
-
|
|
324
|
-
// Random
|
|
325
|
-
uuid: faker.string.uuid(),
|
|
326
|
-
alphanumeric: faker.string.alphanumeric(10),
|
|
327
|
-
hexadecimal: faker.string.hexadecimal(16)
|
|
328
|
-
};
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
**Schema-Based Generation**
|
|
332
|
-
```typescript
|
|
333
|
-
interface User {
|
|
334
|
-
id: string;
|
|
335
|
-
email: string;
|
|
336
|
-
profile: {
|
|
337
|
-
firstName: string;
|
|
338
|
-
lastName: string;
|
|
339
|
-
age: number;
|
|
340
|
-
};
|
|
341
|
-
roles: string[];
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function generateUsers(count: number): User[] {
|
|
345
|
-
return Array.from({ length: count }, () => ({
|
|
346
|
-
id: faker.string.uuid(),
|
|
347
|
-
email: faker.internet.email(),
|
|
348
|
-
profile: {
|
|
349
|
-
firstName: faker.person.firstName(),
|
|
350
|
-
lastName: faker.person.lastName(),
|
|
351
|
-
age: faker.number.int({ min: 18, max: 90 })
|
|
352
|
-
},
|
|
353
|
-
roles: faker.helpers.arrayElements(['user', 'admin', 'moderator'])
|
|
354
|
-
}));
|
|
355
|
-
}
|
|
356
|
-
|
|
357
87
|
// Generate 1000 users
|
|
358
|
-
const users =
|
|
88
|
+
const users = Array.from({ length: 1000 }, generateUser);
|
|
359
89
|
```
|
|
360
90
|
|
|
361
91
|
---
|
|
362
92
|
|
|
363
|
-
|
|
93
|
+
## Test Data Builder Pattern
|
|
364
94
|
|
|
365
|
-
**Builder Pattern**
|
|
366
95
|
```typescript
|
|
367
96
|
class UserBuilder {
|
|
368
97
|
private user: Partial<User> = {};
|
|
369
98
|
|
|
370
|
-
withId(id: string) {
|
|
371
|
-
this.user.id = id;
|
|
372
|
-
return this;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
withEmail(email: string) {
|
|
376
|
-
this.user.email = email;
|
|
377
|
-
return this;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
withRole(role: string) {
|
|
381
|
-
this.user.role = role;
|
|
382
|
-
return this;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
99
|
asAdmin() {
|
|
386
100
|
this.user.role = 'admin';
|
|
387
101
|
this.user.permissions = ['read', 'write', 'delete'];
|
|
@@ -394,395 +108,83 @@ class UserBuilder {
|
|
|
394
108
|
return this;
|
|
395
109
|
}
|
|
396
110
|
|
|
111
|
+
withEmail(email: string) {
|
|
112
|
+
this.user.email = email;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
397
116
|
build(): User {
|
|
398
|
-
// Fill in defaults for missing fields
|
|
399
117
|
return {
|
|
400
118
|
id: this.user.id ?? faker.string.uuid(),
|
|
401
119
|
email: this.user.email ?? faker.internet.email(),
|
|
402
120
|
role: this.user.role ?? 'customer',
|
|
403
|
-
|
|
404
|
-
createdAt: new Date()
|
|
121
|
+
...this.user
|
|
405
122
|
} as User;
|
|
406
123
|
}
|
|
407
124
|
}
|
|
408
125
|
|
|
409
126
|
// Usage
|
|
410
|
-
const admin = new UserBuilder()
|
|
411
|
-
|
|
412
|
-
.withEmail('admin@example.com')
|
|
413
|
-
.build();
|
|
414
|
-
|
|
415
|
-
const customer = new UserBuilder()
|
|
416
|
-
.asCustomer()
|
|
417
|
-
.build();
|
|
418
|
-
|
|
419
|
-
// Flexible, readable, maintainable
|
|
127
|
+
const admin = new UserBuilder().asAdmin().withEmail('admin@test.com').build();
|
|
128
|
+
const customer = new UserBuilder().asCustomer().build();
|
|
420
129
|
```
|
|
421
130
|
|
|
422
131
|
---
|
|
423
132
|
|
|
424
|
-
|
|
133
|
+
## Data Anonymization
|
|
425
134
|
|
|
426
|
-
**Fixture Files**
|
|
427
135
|
```javascript
|
|
428
|
-
//
|
|
429
|
-
export const fixtures = {
|
|
430
|
-
adminUser: {
|
|
431
|
-
id: 1,
|
|
432
|
-
email: 'admin@example.com',
|
|
433
|
-
role: 'admin',
|
|
434
|
-
verified: true
|
|
435
|
-
},
|
|
436
|
-
|
|
437
|
-
regularUser: {
|
|
438
|
-
id: 2,
|
|
439
|
-
email: 'user@example.com',
|
|
440
|
-
role: 'customer',
|
|
441
|
-
verified: true
|
|
442
|
-
},
|
|
443
|
-
|
|
444
|
-
unverifiedUser: {
|
|
445
|
-
id: 3,
|
|
446
|
-
email: 'unverified@example.com',
|
|
447
|
-
role: 'customer',
|
|
448
|
-
verified: false
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
// Use in tests
|
|
453
|
-
import { fixtures } from './fixtures/users';
|
|
454
|
-
|
|
455
|
-
test('admin can delete users', async () => {
|
|
456
|
-
const admin = await createUser(fixtures.adminUser);
|
|
457
|
-
const user = await createUser(fixtures.regularUser);
|
|
458
|
-
|
|
459
|
-
await userService.delete(admin, user.id);
|
|
460
|
-
expect(await db.users.find(user.id)).toBeNull();
|
|
461
|
-
});
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
**Factory Functions**
|
|
465
|
-
```javascript
|
|
466
|
-
// factories/userFactory.js
|
|
467
|
-
export function createUser(overrides = {}) {
|
|
468
|
-
const defaults = {
|
|
469
|
-
id: faker.string.uuid(),
|
|
470
|
-
email: faker.internet.email(),
|
|
471
|
-
firstName: faker.person.firstName(),
|
|
472
|
-
lastName: faker.person.lastName(),
|
|
473
|
-
role: 'customer',
|
|
474
|
-
verified: true,
|
|
475
|
-
createdAt: new Date()
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
return { ...defaults, ...overrides };
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
export function createAdmin(overrides = {}) {
|
|
482
|
-
return createUser({
|
|
483
|
-
role: 'admin',
|
|
484
|
-
permissions: ['read', 'write', 'delete'],
|
|
485
|
-
...overrides
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Use in tests
|
|
490
|
-
test('admin dashboard', async () => {
|
|
491
|
-
const admin = createAdmin({ email: 'specific@example.com' });
|
|
492
|
-
// Test with admin user
|
|
493
|
-
});
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
---
|
|
497
|
-
|
|
498
|
-
## Data Privacy & Compliance
|
|
499
|
-
|
|
500
|
-
### GDPR/CCPA Requirements
|
|
501
|
-
|
|
502
|
-
**What You Must Do:**
|
|
503
|
-
1. **Minimize PII Collection**
|
|
504
|
-
- Only collect necessary data for testing
|
|
505
|
-
- Use synthetic data instead of production data
|
|
506
|
-
- Delete test data after use
|
|
507
|
-
|
|
508
|
-
2. **Secure Storage**
|
|
509
|
-
- Encrypt sensitive test data
|
|
510
|
-
- Access controls on test databases
|
|
511
|
-
- Separate test from production
|
|
512
|
-
|
|
513
|
-
3. **Data Anonymization**
|
|
514
|
-
- Mask/pseudonymize production data if used
|
|
515
|
-
- Remove direct identifiers
|
|
516
|
-
- K-anonymity for aggregate data
|
|
517
|
-
|
|
518
|
-
4. **Right to Erasure**
|
|
519
|
-
- Easy deletion of test accounts
|
|
520
|
-
- Automated cleanup processes
|
|
521
|
-
- Audit trail of deletions
|
|
522
|
-
|
|
523
|
-
**Anonymization Techniques**
|
|
524
|
-
```javascript
|
|
525
|
-
// Data masking
|
|
136
|
+
// Masking
|
|
526
137
|
function maskEmail(email) {
|
|
527
138
|
const [user, domain] = email.split('@');
|
|
528
139
|
return `${user[0]}***@${domain}`;
|
|
529
140
|
}
|
|
530
|
-
|
|
531
|
-
function maskPhone(phone) {
|
|
532
|
-
return phone.replace(/\d(?=\d{4})/g, '*');
|
|
533
|
-
}
|
|
141
|
+
// john@example.com → j***@example.com
|
|
534
142
|
|
|
535
143
|
function maskCreditCard(cc) {
|
|
536
144
|
return `****-****-****-${cc.slice(-4)}`;
|
|
537
145
|
}
|
|
146
|
+
// 4242424242424242 → ****-****-****-4242
|
|
538
147
|
|
|
539
|
-
//
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
function depseudonymize(encrypted, key) {
|
|
548
|
-
const decipher = crypto.createDecipher('aes-256-cbc', key);
|
|
549
|
-
return decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Use in tests
|
|
553
|
-
const user = {
|
|
554
|
-
realEmail: 'john@example.com',
|
|
555
|
-
maskedEmail: maskEmail('john@example.com'), // 'j***@example.com'
|
|
556
|
-
pseudoEmail: pseudonymize('john@example.com', SECRET_KEY)
|
|
557
|
-
};
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
**Data Retention Policies**
|
|
561
|
-
```javascript
|
|
562
|
-
// Auto-delete old test data
|
|
563
|
-
async function cleanupOldTestData() {
|
|
564
|
-
const thirtyDaysAgo = new Date();
|
|
565
|
-
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
|
566
|
-
|
|
567
|
-
// Delete test users older than 30 days
|
|
568
|
-
await db.users.deleteMany({
|
|
569
|
-
email: { $regex: /@example\.com$/ }, // Test emails
|
|
570
|
-
createdAt: { $lt: thirtyDaysAgo }
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
console.log('Cleaned up old test data');
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// Run daily
|
|
577
|
-
schedule.scheduleJob('0 2 * * *', cleanupOldTestData);
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
---
|
|
581
|
-
|
|
582
|
-
## Test Data Lifecycle
|
|
583
|
-
|
|
584
|
-
### Phase 1: Setup/Seeding
|
|
585
|
-
|
|
586
|
-
**Database Seeding**
|
|
587
|
-
```javascript
|
|
588
|
-
// seed.js
|
|
589
|
-
const seedData = {
|
|
590
|
-
users: [
|
|
591
|
-
{ id: 1, email: 'admin@example.com', role: 'admin' },
|
|
592
|
-
{ id: 2, email: 'user@example.com', role: 'customer' }
|
|
593
|
-
],
|
|
594
|
-
products: [
|
|
595
|
-
{ id: 1, name: 'Widget', price: 9.99, inStock: true },
|
|
596
|
-
{ id: 2, name: 'Gadget', price: 19.99, inStock: true }
|
|
597
|
-
]
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
async function seedDatabase() {
|
|
601
|
-
await db.users.insertMany(seedData.users);
|
|
602
|
-
await db.products.insertMany(seedData.products);
|
|
603
|
-
console.log('Database seeded');
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Run before tests
|
|
607
|
-
beforeAll(async () => {
|
|
608
|
-
await seedDatabase();
|
|
609
|
-
});
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
---
|
|
613
|
-
|
|
614
|
-
### Phase 2: Test Execution
|
|
615
|
-
|
|
616
|
-
**Data Isolation During Tests**
|
|
617
|
-
```javascript
|
|
618
|
-
describe('Order Service', () => {
|
|
619
|
-
let testUser;
|
|
620
|
-
let testProduct;
|
|
621
|
-
|
|
622
|
-
beforeEach(async () => {
|
|
623
|
-
// Create fresh data per test
|
|
624
|
-
testUser = await createTestUser();
|
|
625
|
-
testProduct = await createTestProduct();
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
afterEach(async () => {
|
|
629
|
-
// Cleanup after test
|
|
630
|
-
await deleteTestUser(testUser.id);
|
|
631
|
-
await deleteTestProduct(testProduct.id);
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
test('user can place order', async () => {
|
|
635
|
-
const order = await orderService.create({
|
|
636
|
-
userId: testUser.id,
|
|
637
|
-
productId: testProduct.id,
|
|
638
|
-
quantity: 1
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
expect(order.total).toBe(testProduct.price);
|
|
642
|
-
});
|
|
643
|
-
});
|
|
148
|
+
// Anonymize production data
|
|
149
|
+
const anonymizedUsers = prodUsers.map(user => ({
|
|
150
|
+
id: user.id, // Keep ID for relationships
|
|
151
|
+
email: `user-${user.id}@example.com`, // Fake email
|
|
152
|
+
firstName: faker.person.firstName(), // Generated
|
|
153
|
+
phone: null, // Remove PII
|
|
154
|
+
createdAt: user.createdAt // Keep non-PII
|
|
155
|
+
}));
|
|
644
156
|
```
|
|
645
157
|
|
|
646
158
|
---
|
|
647
159
|
|
|
648
|
-
|
|
160
|
+
## Database Transaction Isolation
|
|
649
161
|
|
|
650
|
-
**Transaction-Based Cleanup**
|
|
651
162
|
```javascript
|
|
652
|
-
// Best practice: use transactions
|
|
163
|
+
// Best practice: use transactions for cleanup
|
|
653
164
|
beforeEach(async () => {
|
|
654
165
|
await db.beginTransaction();
|
|
655
166
|
});
|
|
656
167
|
|
|
657
168
|
afterEach(async () => {
|
|
658
|
-
await db.rollbackTransaction(); // Auto cleanup
|
|
659
|
-
});
|
|
660
|
-
```
|
|
661
|
-
|
|
662
|
-
**Manual Cleanup**
|
|
663
|
-
```javascript
|
|
664
|
-
// Track created entities
|
|
665
|
-
const createdIds = {
|
|
666
|
-
users: [],
|
|
667
|
-
orders: [],
|
|
668
|
-
products: []
|
|
669
|
-
};
|
|
670
|
-
|
|
671
|
-
afterEach(async () => {
|
|
672
|
-
// Delete in reverse order (handle foreign keys)
|
|
673
|
-
await db.orders.deleteMany({ id: { $in: createdIds.orders } });
|
|
674
|
-
await db.products.deleteMany({ id: { $in: createdIds.products } });
|
|
675
|
-
await db.users.deleteMany({ id: { $in: createdIds.users } });
|
|
676
|
-
|
|
677
|
-
// Reset tracking
|
|
678
|
-
createdIds.users = [];
|
|
679
|
-
createdIds.orders = [];
|
|
680
|
-
createdIds.products = [];
|
|
169
|
+
await db.rollbackTransaction(); // Auto cleanup!
|
|
681
170
|
});
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
---
|
|
685
|
-
|
|
686
|
-
## Advanced Patterns
|
|
687
|
-
|
|
688
|
-
### Pattern 1: Relational Data Generation
|
|
689
|
-
|
|
690
|
-
**Generate Related Entities**
|
|
691
|
-
```javascript
|
|
692
|
-
async function generateOrderWithRelations() {
|
|
693
|
-
// Create user
|
|
694
|
-
const user = await db.users.create({
|
|
695
|
-
email: faker.internet.email(),
|
|
696
|
-
firstName: faker.person.firstName()
|
|
697
|
-
});
|
|
698
171
|
|
|
699
|
-
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
name: faker.commerce.productName(),
|
|
703
|
-
price: faker.commerce.price()
|
|
704
|
-
}),
|
|
705
|
-
db.products.create({
|
|
706
|
-
name: faker.commerce.productName(),
|
|
707
|
-
price: faker.commerce.price()
|
|
708
|
-
})
|
|
709
|
-
]);
|
|
710
|
-
|
|
711
|
-
// Create order with line items
|
|
712
|
-
const order = await db.orders.create({
|
|
713
|
-
userId: user.id,
|
|
714
|
-
status: 'pending',
|
|
715
|
-
lineItems: products.map(p => ({
|
|
716
|
-
productId: p.id,
|
|
717
|
-
quantity: faker.number.int({ min: 1, max: 5 }),
|
|
718
|
-
price: p.price
|
|
719
|
-
}))
|
|
172
|
+
test('user registration', async () => {
|
|
173
|
+
const user = await userService.register({
|
|
174
|
+
email: 'test@example.com'
|
|
720
175
|
});
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// Use in test
|
|
726
|
-
test('order total calculation', async () => {
|
|
727
|
-
const { order } = await generateOrderWithRelations();
|
|
728
|
-
expect(order.total).toBeGreaterThan(0);
|
|
176
|
+
expect(user.id).toBeDefined();
|
|
177
|
+
// Automatic rollback after test - no cleanup needed
|
|
729
178
|
});
|
|
730
179
|
```
|
|
731
180
|
|
|
732
181
|
---
|
|
733
182
|
|
|
734
|
-
|
|
183
|
+
## Volume Data Generation
|
|
735
184
|
|
|
736
|
-
**Generate Boundary Values**
|
|
737
|
-
```javascript
|
|
738
|
-
function generateEdgeCaseUsers() {
|
|
739
|
-
return [
|
|
740
|
-
// Minimum values
|
|
741
|
-
{
|
|
742
|
-
email: 'a@b.c', // Shortest valid email
|
|
743
|
-
age: 18, // Minimum age
|
|
744
|
-
name: 'A' // Single character
|
|
745
|
-
},
|
|
746
|
-
|
|
747
|
-
// Maximum values
|
|
748
|
-
{
|
|
749
|
-
email: 'a'.repeat(64) + '@' + 'b'.repeat(255), // Max length
|
|
750
|
-
age: 120,
|
|
751
|
-
name: 'A'.repeat(255)
|
|
752
|
-
},
|
|
753
|
-
|
|
754
|
-
// Special characters
|
|
755
|
-
{
|
|
756
|
-
email: "test+tag@example.com",
|
|
757
|
-
name: "O'Brien",
|
|
758
|
-
bio: "Test <script>alert('xss')</script>"
|
|
759
|
-
},
|
|
760
|
-
|
|
761
|
-
// Unicode
|
|
762
|
-
{
|
|
763
|
-
email: 'user@例え.jp',
|
|
764
|
-
name: '山田太郎',
|
|
765
|
-
city: '北京'
|
|
766
|
-
},
|
|
767
|
-
|
|
768
|
-
// Empty/null
|
|
769
|
-
{
|
|
770
|
-
email: 'empty@example.com',
|
|
771
|
-
middleName: null,
|
|
772
|
-
phone: ''
|
|
773
|
-
}
|
|
774
|
-
];
|
|
775
|
-
}
|
|
776
|
-
```
|
|
777
|
-
|
|
778
|
-
---
|
|
779
|
-
|
|
780
|
-
### Pattern 3: Volume Data Generation
|
|
781
|
-
|
|
782
|
-
**Generate Large Datasets**
|
|
783
185
|
```javascript
|
|
784
186
|
// Generate 10,000 users efficiently
|
|
785
|
-
async function
|
|
187
|
+
async function generateLargeDataset(count = 10000) {
|
|
786
188
|
const batchSize = 1000;
|
|
787
189
|
const batches = Math.ceil(count / batchSize);
|
|
788
190
|
|
|
@@ -790,265 +192,79 @@ async function generateLargeUserDataset(count = 10000) {
|
|
|
790
192
|
const users = Array.from({ length: batchSize }, (_, index) => ({
|
|
791
193
|
id: i * batchSize + index,
|
|
792
194
|
email: `user${i * batchSize + index}@example.com`,
|
|
793
|
-
firstName: faker.person.firstName()
|
|
794
|
-
lastName: faker.person.lastName(),
|
|
795
|
-
createdAt: faker.date.past()
|
|
195
|
+
firstName: faker.person.firstName()
|
|
796
196
|
}));
|
|
797
197
|
|
|
798
|
-
// Batch insert
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
console.log(`Inserted batch ${i + 1}/${batches}`);
|
|
198
|
+
await db.users.insertMany(users); // Batch insert
|
|
199
|
+
console.log(`Batch ${i + 1}/${batches}`);
|
|
802
200
|
}
|
|
803
201
|
}
|
|
804
|
-
|
|
805
|
-
// Performance test with realistic volume
|
|
806
|
-
test('search performs well with 10k users', async () => {
|
|
807
|
-
await generateLargeUserDataset(10000);
|
|
808
|
-
|
|
809
|
-
const start = Date.now();
|
|
810
|
-
const results = await userService.search('John');
|
|
811
|
-
const duration = Date.now() - start;
|
|
812
|
-
|
|
813
|
-
expect(duration).toBeLessThan(100); // < 100ms
|
|
814
|
-
});
|
|
815
202
|
```
|
|
816
203
|
|
|
817
204
|
---
|
|
818
205
|
|
|
819
|
-
##
|
|
820
|
-
|
|
821
|
-
### qe-test-data-architect: High-Speed Generation
|
|
206
|
+
## Agent-Driven Data Generation
|
|
822
207
|
|
|
823
|
-
**Generate 10k+ Records per Second**
|
|
824
208
|
```typescript
|
|
825
|
-
//
|
|
826
|
-
|
|
827
|
-
schema: '
|
|
828
|
-
count: 10000,
|
|
829
|
-
|
|
209
|
+
// High-speed generation with constraints
|
|
210
|
+
await Task("Generate Test Data", {
|
|
211
|
+
schema: 'ecommerce',
|
|
212
|
+
count: { users: 10000, products: 500, orders: 5000 },
|
|
213
|
+
preserveReferentialIntegrity: true,
|
|
830
214
|
constraints: {
|
|
831
215
|
age: { min: 18, max: 90 },
|
|
832
|
-
roles: ['customer', 'admin'
|
|
833
|
-
emailDomain: 'example.com'
|
|
216
|
+
roles: ['customer', 'admin']
|
|
834
217
|
}
|
|
835
|
-
});
|
|
836
|
-
|
|
837
|
-
// Returns 10,000 fully populated user records
|
|
838
|
-
// With relationships, constraints, realistic patterns
|
|
839
|
-
```
|
|
840
|
-
|
|
841
|
-
**Edge Case Discovery**
|
|
842
|
-
```typescript
|
|
843
|
-
// Agent auto-discovers edge cases
|
|
844
|
-
const edgeCases = await agent.generateEdgeCases({
|
|
845
|
-
field: 'email',
|
|
846
|
-
patterns: [
|
|
847
|
-
'special-chars',
|
|
848
|
-
'unicode',
|
|
849
|
-
'max-length',
|
|
850
|
-
'min-length',
|
|
851
|
-
'sql-injection',
|
|
852
|
-
'xss-attempts'
|
|
853
|
-
]
|
|
854
|
-
});
|
|
855
|
-
|
|
856
|
-
// Returns comprehensive edge case dataset
|
|
857
|
-
// 50+ edge cases for email field
|
|
858
|
-
```
|
|
218
|
+
}, "qe-test-data-architect");
|
|
859
219
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
source: productionSnapshot,
|
|
865
|
-
piiFields: ['email', 'phone', 'ssn', 'address'],
|
|
220
|
+
// GDPR-compliant anonymization
|
|
221
|
+
await Task("Anonymize Production Data", {
|
|
222
|
+
source: 'production-snapshot',
|
|
223
|
+
piiFields: ['email', 'phone', 'ssn'],
|
|
866
224
|
method: 'pseudonymization',
|
|
867
225
|
retainStructure: true
|
|
868
|
-
});
|
|
869
|
-
|
|
870
|
-
// Returns anonymized data maintaining referential integrity
|
|
226
|
+
}, "qe-test-data-architect");
|
|
871
227
|
```
|
|
872
228
|
|
|
873
229
|
---
|
|
874
230
|
|
|
875
|
-
|
|
231
|
+
## Agent Coordination Hints
|
|
876
232
|
|
|
233
|
+
### Memory Namespace
|
|
234
|
+
```
|
|
235
|
+
aqe/test-data-management/
|
|
236
|
+
├── schemas/* - Data schemas
|
|
237
|
+
├── generators/* - Generator configs
|
|
238
|
+
├── anonymization/* - PII handling rules
|
|
239
|
+
└── fixtures/* - Reusable fixtures
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Fleet Coordination
|
|
877
243
|
```typescript
|
|
878
|
-
// Multiple agents coordinate for complex data
|
|
879
244
|
const dataFleet = await FleetManager.coordinate({
|
|
880
245
|
strategy: 'test-data-generation',
|
|
881
246
|
agents: [
|
|
882
|
-
'qe-test-data-architect', // Generate
|
|
883
|
-
'qe-test-
|
|
884
|
-
'qe-
|
|
247
|
+
'qe-test-data-architect', // Generate data
|
|
248
|
+
'qe-test-executor', // Execute with data
|
|
249
|
+
'qe-security-scanner' // Validate no PII exposure
|
|
885
250
|
],
|
|
886
251
|
topology: 'sequential'
|
|
887
252
|
});
|
|
888
|
-
|
|
889
|
-
await dataFleet.execute({
|
|
890
|
-
scenario: 'e-commerce-checkout',
|
|
891
|
-
volume: {
|
|
892
|
-
users: 1000,
|
|
893
|
-
products: 500,
|
|
894
|
-
orders: 5000
|
|
895
|
-
},
|
|
896
|
-
relationships: true,
|
|
897
|
-
realistic: true
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
// Generates full data graph:
|
|
901
|
-
// - 1000 users with profiles
|
|
902
|
-
// - 500 products with inventory
|
|
903
|
-
// - 5000 orders with line items
|
|
904
|
-
// - All relationships maintained
|
|
905
|
-
// - Tests generated and executed
|
|
906
253
|
```
|
|
907
254
|
|
|
908
255
|
---
|
|
909
256
|
|
|
910
|
-
## Tools & Libraries
|
|
911
|
-
|
|
912
|
-
### Data Generation
|
|
913
|
-
- **@faker-js/faker** - Comprehensive fake data generation
|
|
914
|
-
- **Mockaroo** - Online data generator (CSV, JSON, SQL)
|
|
915
|
-
- **Chance.js** - Random data generation
|
|
916
|
-
- **Casual** - Minimalist fake data
|
|
917
|
-
- **JSON Schema Faker** - Generate from JSON schemas
|
|
918
|
-
|
|
919
|
-
### Database Tools
|
|
920
|
-
- **Factory Bot** (Ruby) - Test data factories
|
|
921
|
-
- **FactoryGuy** (JavaScript) - Ember.js factories
|
|
922
|
-
- **Fishery** (TypeScript) - Type-safe factories
|
|
923
|
-
- **Knex.js** - SQL query builder with seeding
|
|
924
|
-
- **Prisma** - ORM with seeding support
|
|
925
|
-
|
|
926
|
-
### Privacy Tools
|
|
927
|
-
- **ARX Data Anonymization Tool** - GDPR compliance
|
|
928
|
-
- **sdv (Synthetic Data Vault)** - AI-generated synthetic data
|
|
929
|
-
- **Presidio** - PII detection and anonymization
|
|
930
|
-
- **Faker** - Built-in data masking
|
|
931
|
-
|
|
932
|
-
---
|
|
933
|
-
|
|
934
|
-
## Common Pitfalls
|
|
935
|
-
|
|
936
|
-
### ❌ Using Production Data Directly
|
|
937
|
-
```javascript
|
|
938
|
-
// NEVER do this
|
|
939
|
-
const prodUsers = await prodDb.query('SELECT * FROM users');
|
|
940
|
-
await testDb.insertMany(prodUsers); // ⚠️ PII violation
|
|
941
|
-
```
|
|
942
|
-
|
|
943
|
-
**Fix:** Anonymize first or use synthetic data
|
|
944
|
-
|
|
945
|
-
### ❌ Not Cleaning Up Test Data
|
|
946
|
-
```javascript
|
|
947
|
-
// Creates 100 users per test, never deleted
|
|
948
|
-
test('many tests', async () => {
|
|
949
|
-
const users = await generateUsers(100);
|
|
950
|
-
// ... test code
|
|
951
|
-
// No cleanup! Database fills up
|
|
952
|
-
});
|
|
953
|
-
```
|
|
954
|
-
|
|
955
|
-
**Fix:** Use transactions or cleanup hooks
|
|
956
|
-
|
|
957
|
-
### ❌ Hard-Coded IDs
|
|
958
|
-
```javascript
|
|
959
|
-
// Breaks when run in parallel or multiple times
|
|
960
|
-
const user = await createUser({ id: 1 }); // ⚠️ Collision risk
|
|
961
|
-
```
|
|
962
|
-
|
|
963
|
-
**Fix:** Use generated UUIDs or auto-increment
|
|
964
|
-
|
|
965
|
-
### ❌ Shared Mutable Data
|
|
966
|
-
```javascript
|
|
967
|
-
// Tests pollute shared data
|
|
968
|
-
const sharedUser = createUser();
|
|
969
|
-
|
|
970
|
-
test('update email', () => {
|
|
971
|
-
sharedUser.email = 'new@example.com'; // Affects other tests!
|
|
972
|
-
});
|
|
973
|
-
```
|
|
974
|
-
|
|
975
|
-
**Fix:** Create fresh data per test
|
|
976
|
-
|
|
977
|
-
---
|
|
978
|
-
|
|
979
|
-
## Best Practices Checklist
|
|
980
|
-
|
|
981
|
-
**Data Generation:**
|
|
982
|
-
- [ ] Use faker or similar library for realistic data
|
|
983
|
-
- [ ] Generate data with proper constraints
|
|
984
|
-
- [ ] Create both minimal and realistic datasets
|
|
985
|
-
- [ ] Include edge cases and boundary values
|
|
986
|
-
- [ ] Use builders/factories for complex entities
|
|
987
|
-
|
|
988
|
-
**Privacy & Compliance:**
|
|
989
|
-
- [ ] Never use production PII directly
|
|
990
|
-
- [ ] Anonymize/pseudonymize production data snapshots
|
|
991
|
-
- [ ] Use synthetic data as default
|
|
992
|
-
- [ ] Implement data retention policies
|
|
993
|
-
- [ ] Document data handling procedures
|
|
994
|
-
|
|
995
|
-
**Performance:**
|
|
996
|
-
- [ ] Batch insert for large datasets
|
|
997
|
-
- [ ] Use database transactions for isolation
|
|
998
|
-
- [ ] Generate data lazily when possible
|
|
999
|
-
- [ ] Cache commonly used fixtures
|
|
1000
|
-
- [ ] Clean up data after tests
|
|
1001
|
-
|
|
1002
|
-
**Maintainability:**
|
|
1003
|
-
- [ ] Centralize test data generation
|
|
1004
|
-
- [ ] Version control seed data
|
|
1005
|
-
- [ ] Document data schemas
|
|
1006
|
-
- [ ] Use type-safe factories (TypeScript)
|
|
1007
|
-
- [ ] Keep data generation DRY
|
|
1008
|
-
|
|
1009
|
-
---
|
|
1010
|
-
|
|
1011
257
|
## Related Skills
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
- [
|
|
1015
|
-
- [test-environment-management](../test-environment-management/) - Environments need data
|
|
1016
|
-
- [database-testing](../database-testing/) - Database schema and data integrity
|
|
1017
|
-
|
|
1018
|
-
**Testing Methodologies:**
|
|
1019
|
-
- [regression-testing](../regression-testing/) - Regression needs stable test data
|
|
1020
|
-
- [performance-testing](../performance-testing/) - Performance tests need volume data
|
|
1021
|
-
- [api-testing-patterns](../api-testing-patterns/) - API tests need request data
|
|
1022
|
-
|
|
1023
|
-
**Quality Management:**
|
|
1024
|
-
- [agentic-quality-engineering](../agentic-quality-engineering/) - Agent-driven data generation
|
|
1025
|
-
- [compliance-testing](../compliance-testing/) - GDPR/CCPA compliance validation
|
|
258
|
+
- [database-testing](../database-testing/) - Schema and integrity testing
|
|
259
|
+
- [compliance-testing](../compliance-testing/) - GDPR/CCPA compliance
|
|
260
|
+
- [performance-testing](../performance-testing/) - Volume data for perf tests
|
|
1026
261
|
|
|
1027
262
|
---
|
|
1028
263
|
|
|
1029
264
|
## Remember
|
|
1030
265
|
|
|
1031
|
-
**Test data is infrastructure, not an afterthought.**
|
|
1032
|
-
|
|
1033
|
-
Poor test data causes:
|
|
1034
|
-
- 40% of test failures
|
|
1035
|
-
- Hours wasted debugging
|
|
1036
|
-
- Unreliable test results
|
|
1037
|
-
- Privacy violations
|
|
1038
|
-
- Scaling bottlenecks
|
|
1039
|
-
|
|
1040
|
-
**Good test data management enables:**
|
|
1041
|
-
- Fast, reliable tests
|
|
1042
|
-
- Realistic scenarios
|
|
1043
|
-
- Privacy compliance
|
|
1044
|
-
- Scalable testing
|
|
1045
|
-
- Confident deployments
|
|
266
|
+
**Test data is infrastructure, not an afterthought.** 40% of test failures are caused by inadequate test data. Poor data = poor tests.
|
|
1046
267
|
|
|
1047
|
-
**
|
|
1048
|
-
1. Never use production PII
|
|
1049
|
-
2. Automate data generation
|
|
1050
|
-
3. Clean up after tests
|
|
1051
|
-
4. Use transactions for isolation
|
|
1052
|
-
5. Generate edge cases systematically
|
|
268
|
+
**Never use production PII directly.** GDPR fines up to €20M or 4% of revenue. Always use synthetic data or properly anonymized production snapshots.
|
|
1053
269
|
|
|
1054
|
-
**With Agents:** `qe-test-data-architect` generates 10k+ records/sec with realistic patterns,
|
|
270
|
+
**With Agents:** `qe-test-data-architect` generates 10k+ records/sec with realistic patterns, relationships, and constraints. Agents ensure GDPR/CCPA compliance automatically and eliminate test data bottlenecks.
|