Creating tests in real database with NestJS, TypeORM and PostgreSQL
Gabriel Couto
Posted on October 4, 2024
Intro
Whether you are in a test-driven development mode or not, there are a few useful perks in writing tests:
They provide a safety net that allows developers to confidently make changes, add new features, refactor code knowing that the tests will verify the functionality remains intact.
The pain
Some of us aren't blessed with high-end cpus, and that can't be especially frustating when dealing with huge projects.
Recently i was working in a huge NestJS app, and i just wanted to test some TypeORM Queryes and every time i modified i had to load the entire project. Think of an frustation face, that was me.
Solution
Writing tests is a good pratice, right? what if i could develop faster and indirectly create tests and also avoid the need to create mocks and stubs ? Thats when i thought: Tests agaisnt the real database.
Code
Here is the tests:
import * as dotenv from 'dotenv';
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
dotenv.config();
describe('Queryes only test', () => {
let app: INestApplication;
let foodRepo: FoodRepository;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRootAsync({
useFactory: (configService: any) => ({
type: 'postgres',
host: process.env.TYPEORM_HOST,
port: Number(process.env.TYPEORM_PORT),
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE,
entities: ['src/app/**/entities/*.entity.*'],
synchronize: false,
logging: true /* That will make the sql queryes appear in the console */
})
}),
TypeOrmModule.forFeature([FoodRepository])
]
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
foodRepo = moduleFixture.get<FoodRepository>(FoodRepository);
});
jest.setTimeout(30000);
it('Must find foods from regular customers', async () => {
const foodsFromRegularCustomers = await foodRepo.findFoodsFromRegularCustomers().getMany();
expect(Array.isArray(foodsFromRegularCustomers)).toBeTruthy();
});
afterAll(async () => {
await app.close();
});
});
and thats my repository:
async findFoodsFromRegularCustomers() {
const currentDate = new Date();
const startOfWeek = new Date(currentDate.setDate(currentDate.getDate() - currentDate.getDay()));
return this.createQueryBuilder('food')
.innerJoin('food.customer', 'customer')
.innerJoin('customer.orders', 'orders')
.select([
'customer.id',
'customer.name',
'customer.cpf',
'customer.address'
])
.where('orders.createdAt >= :startOfWeek', { startOfWeek })
.groupBy('customer.id')
.having('COUNT(orders.id) > :minOrders', { minOrders: 10 })
}
That test must not be the perfection, but i assure you:
It will help the developer team avoid send broken querys.
If some entity attribute or relationship stop existing, like customer.address
the query builder won't break in build time. But the tests will.😼
Posted on October 4, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.