Testing with a database helps ensure your app works well with real data. Using test databases keeps your real data safe and your tests reliable.
Test database strategies in NestJS
import { Test } from '@nestjs/testing'; import { TypeOrmModule } from '@nestjs/typeorm'; await Test.createTestingModule({ imports: [ TypeOrmModule.forRoot({ type: 'sqlite', database: ':memory:', entities: [YourEntity], synchronize: true, }), TypeOrmModule.forFeature([YourEntity]), ], providers: [YourService], }).compile();
Use an in-memory database like SQLite for fast, isolated tests.
Set synchronize: true to auto-create tables during tests.
TypeOrmModule.forRoot({
type: 'sqlite',
database: ':memory:',
entities: [User],
synchronize: true,
})TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'test',
password: 'test',
database: 'test_db',
entities: [User],
synchronize: true,
})await connection.dropDatabase(); await connection.synchronize();
This example shows a NestJS test setup using an in-memory SQLite database. It creates a user and fetches all users to verify database operations work in tests.
import { Test } from '@nestjs/testing'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity() class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; } @Injectable() class UserService { constructor( @InjectRepository(User) private repo: Repository<User>, ) {} async createUser(name: string) { const user = this.repo.create({ name }); return this.repo.save(user); } async findAll() { return this.repo.find(); } } async function bootstrap() { const moduleRef = await Test.createTestingModule({ imports: [ TypeOrmModule.forRoot({ type: 'sqlite', database: ':memory:', entities: [User], synchronize: true, }), TypeOrmModule.forFeature([User]), ], providers: [UserService], }).compile(); const userService = moduleRef.get(UserService); await userService.createUser('Alice'); const users = await userService.findAll(); console.log(users); } bootstrap();
Use an in-memory database for fast tests that don't affect real data.
Reset the database state before each test to avoid test interference.
For complex tests, consider using a dedicated test database server.
Test databases keep your real data safe during testing.
In-memory databases like SQLite are fast and easy for tests.
Resetting the database before tests keeps tests independent and reliable.
Practice
Why do we use a separate test database in NestJS applications?
Solution
Step 1: Understand the purpose of test databases
Test databases are used to isolate testing data from real data to prevent accidental data loss or corruption.Step 2: Identify the main reason for using test databases in NestJS
Using a separate test database ensures tests do not affect production data, keeping it safe.Final Answer:
To keep real data safe and avoid accidental changes during tests -> Option BQuick Check:
Test database = Protect real data [OK]
- Thinking test DB improves production speed
- Confusing test DB with security for passwords
- Assuming test DB reduces main DB size
Which of the following is the correct way to configure an in-memory SQLite database for testing in a NestJS TypeOrmModule?
TypeOrmModule.forRoot({
type: 'sqlite',
database: ???,
entities: [User],
synchronize: true,
})Solution
Step 1: Recall SQLite in-memory database syntax
SQLite uses ':memory:' as the special name to create a temporary in-memory database.Step 2: Match the correct database name in the config
Using ':memory:' tells TypeORM to use an in-memory DB for fast, isolated tests.Final Answer:
':memory:' -> Option DQuick Check:
SQLite in-memory DB = ':memory:' [OK]
- Using a file name instead of ':memory:'
- Confusing ':disk:' as valid SQLite option
- Using arbitrary file names like 'memory.db'
Given this NestJS test setup snippet, what will be the output of console.log(users.length) inside the test?
beforeEach(async () => {
await connection.synchronize(true); // resets DB
await userRepository.save([{ name: 'Alice' }, { name: 'Bob' }]);
});
test('users count', async () => {
const users = await userRepository.find();
console.log(users.length);
});Solution
Step 1: Understand what synchronize(true) does
Calling synchronize(true) resets the database, clearing all data before each test.Step 2: Analyze the data saved before the test
After reset, two users 'Alice' and 'Bob' are saved, so the DB has 2 users.Step 3: Check the find() result
Finding all users returns an array of length 2.Final Answer:
2 -> Option CQuick Check:
Reset + save 2 users = 2 users found [OK]
- Assuming DB is not reset and counting old data
- Thinking synchronize(true) deletes data after save
- Expecting undefined because of async confusion
What is the main problem with this test database setup code snippet?
beforeAll(async () => {
await connection.synchronize(true);
});
afterAll(async () => {
await connection.close();
});
test('should save user', async () => {
await userRepository.save({ name: 'Charlie' });
const users = await userRepository.find();
expect(users.length).toBe(1);
});
test('should find no users initially', async () => {
const users = await userRepository.find();
expect(users.length).toBe(0);
});Solution
Step 1: Analyze when the database reset happens
Database reset with synchronize(true) is done only once before all tests, not before each test.Step 2: Understand test data persistence
Data saved in the first test remains in the DB during the second test, causing unexpected results.Final Answer:
Database is reset only once before all tests, causing data to persist between tests -> Option AQuick Check:
Reset once beforeAll causes data carryover [OK]
- Thinking connection closes too early
- Assuming userRepository is undefined
- Believing tests run in parallel causing race
You want to ensure each test in your NestJS app runs with a clean database state using an in-memory SQLite DB. Which strategy best achieves this?
- Use
TypeOrmModule.forRootwithdatabase: ':memory:' - Reset the database schema before each test
- Close and reopen the connection before each test
- Seed only required test data inside each test
Which combination of these steps is best practice?
Solution
Step 1: Use in-memory DB for fast isolated tests
Setting database to ':memory:' creates a fresh DB in memory for each connection.Step 2: Reset schema before each test
Resetting schema ensures no leftover data or schema changes affect tests.Step 3: Close and reopen connection before each test
Reopening connection resets the in-memory DB state fully.Step 4: Seed only needed data per test
Seeding minimal data keeps tests independent and fast.Final Answer:
All steps 1, 2, 3, and 4 -> Option AQuick Check:
Full reset + seed per test = reliable tests [OK]
- Skipping connection reopen causing stale DB
- Not resetting schema before tests
- Seeding too much data globally
Ready to prove it?
Pass the test and this pattern moves unknown
