Configurando testes de integração no Nestjs com o Typeorm
Tags: testing, typescript, todayilearned
Published: 2022-06-16 00:59:10

## 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

```js
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

```js
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

```js
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

```js
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