Quick Tips
3 min
Test Data Management Strategies
Effective approaches to managing test data for reliable and maintainable tests
...
test-datatestingbest-practicesautomation
Test Data Management Best Practices
1. Data Builders Pattern
Create flexible test data on-the-fly:
class UserBuilder {
constructor() {
this.data = {
email: `user${Date.now()}@test.com`,
name: 'Test User',
age: 25,
role: 'user',
};
}
withEmail(email) {
this.data.email = email;
return this;
}
withRole(role) {
this.data.role = role;
return this;
}
build() {
return this.data;
}
}
// Usage
const admin = new UserBuilder()
.withEmail('admin@test.com')
.withRole('admin')
.build();2. Fixture Files
Store static test data in JSON files:
// fixtures/users.json
{
"validUser": {
"email": "valid@example.com",
"password": "ValidPass123!"
},
"adminUser": {
"email": "admin@example.com",
"password": "AdminPass123!"
}
}
// In tests
import users from './fixtures/users.json';
test('login with valid user', async () => {
await login(users.validUser);
expect(await isLoggedIn()).toBe(true);
});3. Factory Functions
Generate random but valid data:
import { faker } from '@faker-js/faker';
function createUser(overrides = {}) {
return {
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: faker.date.recent(),
...overrides,
};
}
// Usage
const user1 = createUser({ email: 'specific@email.com' });
const user2 = createUser(); // Random data4. Database Seeding
Prepare consistent database state:
// seeds/testUsers.js
export async function seedUsers(db) {
await db.users.deleteMany({}); // Clean start
await db.users.createMany([
{ email: 'test1@example.com', role: 'user' },
{ email: 'test2@example.com', role: 'user' },
{ email: 'admin@example.com', role: 'admin' },
]);
}
// In tests
beforeEach(async () => {
await seedUsers(db);
});5. Test Data Cleanup
Always clean up to prevent test interference:
describe('User tests', () => {
const createdUsers = [];
afterEach(async () => {
// Clean up all created users
for (const user of createdUsers) {
await deleteUser(user.id);
}
createdUsers.length = 0;
});
test('create user', async () => {
const user = await createUser(userData);
createdUsers.push(user); // Track for cleanup
expect(user.id).toBeDefined();
});
});Key Principles
- Isolation: Each test creates its own data
- Idempotency: Tests produce same result every run
- Cleanup: Remove test data after use
- Realistic: Use data similar to production
- Minimal: Only create data you actually need
Anti-Patterns to Avoid
- ❌ Hardcoding production IDs
- ❌ Sharing data between tests
- ❌ Leaving test data in database
- ❌ Using unrealistic data
- ❌ Over-complicated data setups
Pro Tips
- Use faker for realistic random data
- Keep fixtures small and focused
- Document data dependencies
- Use transactions for faster cleanup
- Consider using test containers for databases
Comments (0)
Loading comments...