Teste de integração
Testes de integração como o nome já dá uma noção, são testes integrados com serviços externos, então por exemplo: em um teste unitário eu faço o mock do retorno do banco de dados para não precisar me conectar no banco de dados e fazer as queries. Enquanto nos testes de integração a ideia é subir um banco de dados separado só para teste e rodar e depois destruir esse banco.
Por que usar o teste de integração? tive essa necessidade principalmente pois os testes unitários não me deixaram confortável em garantir o pleno funcionamento da aplicação. Em alguns endpoints onde a função principal era fazer uma busca paginada por exemplo os testes unitários não bastavam pois o que mais importa nessa função é a querie que vai rodar no banco e as suas variações com filtros, e no teste unitário como eu que defino o retorno que a função vai ter não ia ter como testar isso.
Fazendo as configurações
Primeiro precisei configurar uma conexão 'mãe' que vai ser responsável por criar o banco de dados, e também configurar uma conexão secundaria que vai ser a conexão com o banco de testes
const masterConnection = new DataSource({
type: 'postgres',
database: process.env.DATABASE_NAME,
host: process.env.DATABASE_HOST,
password: process.env.DATABASE_PASSWORD,
port: process.env.DATABASE_PORT
? parseInt(process.env.DATABASE_PORT, 10)
: undefined,
username: process.env.DATABASE_USERNAME,
entities: ['dist/**/*.entity{.ts,.js}'],
migrations: ['dist/src/db/migrations/*.js'],
logging: false,
name: 'master',
migrationsRun: false,
});
const connection = new DataSource({
...(masterConnection.options as PostgresConnectionOptions),
database: databaseName,
migrationsRun: true,
name: undefined,
});
e então fiz uma função para fazer a conexão e criar o banco de dados o banco de dados e gerei um nome aleatório para o banco
Não é obrigatório gerar um nome aleatório pois ainda vou apagar o banco de testes quando acabar com teste poderia também ser um nome definido como 'test_db' por exemplo
Nessa função fazemos a conexão que vai gerar o banco, geramos ele e retornamos a conexão com esse banco gerado
const databaseName = `test_${randomBytes(8).toString('hex')}`;
export async function databaseIntegrationSetup() {
try {
await masterConnection.initialize();
await masterConnection.query(`CREATE DATABASE "${databaseName}"`);
} catch (err) {
process.stderr.write(
`${err instanceof Error ? err.stack : JSON.stringify(err)}\n`,
);
process.exit(1);
}
return connection;
}
E uma função para fechar a conexão com o banco de dados, onde ele dropa o database criado para testes e fecha a conexão
export async function closeDatabaseIntegrationConnections() {
try {
await masterConnection.query(`DROP DATABASE "${databaseName}"`);
await masterConnection.destroy();
} catch (err) {
process.stderr.write(
`${err instanceof Error ? err.stack : JSON.stringify(err)}\n`,
);
process.exit(1);
}
}
Inicializando o teste
describe('Integrations tests', () => {
let app: INestApplication;
jest.setTimeout(30000);
beforeAll(async () => {
const databaseConnection = await databaseIntegrationSetup();
const module: TestingModule = await Test.createTestingModule({
imports: [TypeOrmModule.forRoot(databaseConnection.options)],
}).compile();
app = module.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
await closeDatabaseIntegrationConnections();
});
it('should be defined', async () => {
expect(app).toBeDefined();
});
});
Para definirmos o teste a gente basicamente vai pegar a conexão com o database que retornamos na primeira função e vamos declarar um modulo de testes e passar essa conexão para o modulo do Typeorm, e vamos inicializar o app nesse momento o teste já vai passar, porem depois de todos os testes rodarem precisamos fechar o app e chamar a função de fechar a conexão com o banco de dados e apagar esse banco criado só para testes
Top comments (0)