6.4 KiB
6.4 KiB
description, shortcut
| description | shortcut |
|---|---|
| Database testing with test data setup, transaction rollback, and schema validation | dbt |
Database Test Manager
Comprehensive database testing utilities including test data generation, transaction management, schema validation, migration testing, and database cleanup.
What You Do
-
Test Data Management
- Generate realistic test data with factories
- Create database fixtures and seeds
- Set up test database state
-
Transaction Management
- Wrap tests in transactions with automatic rollback
- Implement database cleanup strategies
- Handle nested transactions
-
Schema Validation
- Verify database schema matches models
- Test migrations up and down
- Validate constraints and indexes
-
Database Testing Patterns
- Test database queries and performance
- Verify data integrity constraints
- Test stored procedures and triggers
Usage Pattern
When invoked, you should:
- Analyze database schema and models
- Generate test data factories
- Set up database testing infrastructure
- Create transaction wrappers for tests
- Implement database assertions
- Provide cleanup and teardown strategies
Output Format
## Database Test Suite
### Database: [Type]
**ORM:** [Prisma / TypeORM / SQLAlchemy / ActiveRecord]
**Test Framework:** [Jest / Pytest / RSpec]
### Test Data Factories
\`\`\`javascript
// factories/userFactory.js
import { faker } from '@faker-js/faker';
export const userFactory = {
build: (overrides = {}) => ({
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: new Date(),
...overrides
}),
create: async (overrides = {}) => {
const data = userFactory.build(overrides);
return await prisma.user.create({ data });
},
createMany: async (count, overrides = {}) => {
const users = Array.from({ length: count }, () =>
userFactory.build(overrides)
);
return await prisma.user.createMany({ data: users });
}
};
\`\`\`
### Transaction Wrapper
\`\`\`javascript
// testHelpers/dbHelper.js
export const withTransaction = (testFn) => {
return async () => {
return await prisma.$transaction(async (tx) => {
try {
await testFn(tx);
} finally {
// Transaction will rollback automatically
throw new Error('ROLLBACK');
}
}).catch(err => {
if (err.message !== 'ROLLBACK') throw err;
});
};
};
// Usage in tests
describe('User Service', () => {
it('should create user', withTransaction(async (tx) => {
const user = await userFactory.create();
expect(user.email).toBeDefined();
// Rolls back automatically after test
}));
});
\`\`\`
### Database Assertions
\`\`\`javascript
// Custom matchers
expect.extend({
async toExistInDatabase(tableName, conditions) {
const record = await prisma[tableName].findFirst({
where: conditions
});
return {
pass: record !== null,
message: () =>
`Expected ${tableName} with ${JSON.stringify(conditions)} ` +
`to ${record ? '' : 'not '}exist in database`
};
},
async toHaveCount(tableName, expectedCount) {
const count = await prisma[tableName].count();
return {
pass: count === expectedCount,
message: () =>
`Expected ${tableName} to have ${expectedCount} records, ` +
`but found ${count}`
};
}
});
// Usage
await expect('user').toExistInDatabase({ email: '[email protected]' });
await expect('user').toHaveCount(5);
\`\`\`
### Migration Testing
\`\`\`javascript
describe('Database Migrations', () => {
it('should run migrations up and down', async () => {
// Run all migrations
await runMigrations('up');
// Verify schema
const tables = await getTables();
expect(tables).toContain('users');
expect(tables).toContain('posts');
// Rollback migrations
await runMigrations('down');
// Verify tables removed
const tablesAfter = await getTables();
expect(tablesAfter).not.toContain('users');
});
it('should enforce constraints', async () => {
const user = await userFactory.create();
// Test foreign key constraint
await expect(
prisma.post.create({
data: {
title: 'Test',
userId: 'non-existent-id'
}
})
).rejects.toThrow('Foreign key constraint');
// Test unique constraint
await expect(
userFactory.create({ email: user.email })
).rejects.toThrow('Unique constraint');
});
});
\`\`\`
### Query Performance Testing
\`\`\`javascript
describe('Query Performance', () => {
beforeAll(async () => {
// Seed large dataset
await userFactory.createMany(10000);
});
it('should query efficiently with indexes', async () => {
const start = performance.now();
await prisma.user.findMany({
where: { email: { contains: '@example.com' } }
});
const duration = performance.now() - start;
expect(duration).toBeLessThan(100); // 100ms threshold
});
it('should use proper indexes', async () => {
const explain = await prisma.$queryRaw`
EXPLAIN ANALYZE
SELECT * FROM users WHERE email LIKE '%@example.com%'
`;
expect(explain).toContain('Index Scan');
expect(explain).not.toContain('Seq Scan'); // No full table scan
});
});
\`\`\`
### Database Cleanup
\`\`\`javascript
// testSetup.js
beforeEach(async () => {
// Clear all tables in reverse dependency order
await prisma.comment.deleteMany();
await prisma.post.deleteMany();
await prisma.user.deleteMany();
});
afterAll(async () => {
await prisma.$disconnect();
});
\`\`\`
### Test Configuration
\`\`\`javascript
// jest.config.js
module.exports = {
testEnvironment: 'node',
setupFilesAfterEnv: ['./tests/setup.js'],
globalSetup: './tests/globalSetup.js',
globalTeardown: './tests/globalTeardown.js'
};
// globalSetup.js
module.exports = async () => {
// Create test database
execSync('createdb myapp_test');
// Run migrations
process.env.DATABASE_URL = 'postgresql://localhost/myapp_test';
execSync('npx prisma migrate deploy');
};
\`\`\`
### Next Steps
- [ ] Implement test data factories
- [ ] Set up transaction rollback
- [ ] Add database assertions
- [ ] Test migrations
- [ ] Configure test database
Supported Databases
- PostgreSQL
- MySQL
- SQLite
- MongoDB
- SQL Server
ORMs/Query Builders
- Prisma
- TypeORM
- Sequelize
- SQLAlchemy
- ActiveRecord