Node.js Test Tipps - MongoDB

Ich möchte den Blick erneut auf das Testen richten. Jegliche Form des Qualitätsdenkens beginnt meiner Meinung nach damit. Dieses Mal möchte ich zeigen, welche Hilfsmittel ich bei der Arbeit mit MongoDB einsetze. Ich zeige, wie ich mein Setup aufbaue, um performante Integrationstests zu ermöglichen.

3 Minuten

In einem vorherigen Artikel (Repositories mit Prisma) hatte ich das Entwicklungsmuster der Repositories vorgestellt. Im Rahmen der Unit-Tests mocke ich auf dieser Ebene und treffe Annahmen dazu, was aus dem Repository geliefert wird und ob mein Code mit den Ergebnissen arbeiten kann.

Dieses Mal beabsichtige ich, einen Schritt zurückzutreten. Die Testausführung soll die Annahmen, die ich in den Unittests treffe, beweisen. D. h., ich will Tests schreiben, in denen ich Daten in eine MongoDB schreibe, wiederlese und sicherstelle, dass die Informationen so aussehen, wie ich es erwarte.

Wie bereits im Artikel über das Dateisystem angedeutet, spielt die Testperformanz eine große Rolle. Deswegen – und aus anderen Gründen – ist die Nutzung einer MongoDB-Instanz keine Option. Die In-Memory-Variante muss her und passend konfiguriert sein.

Das MongoDB-Test-Setup in Verbindung mit Prisma

Zuerst sind einige NPM-Pakete zu installieren:

  1. mongodb-memory-server für die In-Memory-MongoDB-Variante
  2. mongoose für die Interaktion mit der MongoDB beim Testsetup

Als Nächstes legen wir eine MongoDB-Konfiguration namens monogoConfig.ts für die Tests an:

const config = {
  memory: true,
  ip: '127.0.0.1',
  port: '27017',
  database: 'testDb',
  replSet: true,
}

export default config

Im Rahmen des globalen Setups von Vitest bereiten wir die In-Memory-MongoDB vor, setzen die notwendigen Environment-Variablen für Prisma und stecken dies alles zusammen in die für Vitest vorgesehenen Methoden (siehe Vitest-Dokumentation):

import { MongoMemoryReplSet, MongoMemoryServer } from 'mongodb-memory-server'
import mongoose from 'mongoose'

import mongoConfig from './database/mongoConfig' // change according to your structure

mongoose.set('strictQuery', true)

declare global {
  var __MONGOINSTANCE: MongoMemoryReplSet | MongoMemoryServer
}

export async function setup() {
  // Config to decided if a mongodb-memory-server instance should be used
  // it's needed in global space, because we don't want to create a new instance every test-suite
  if (mongoConfig.memory) {
    const instance = mongoConfig.replSet
      ? await MongoMemoryReplSet.create({ replSet: { count: 2, storageEngine: 'wiredTiger' } })
      : await MongoMemoryServer.create()
    const uri = instance.getUri()

    global.__MONGOINSTANCE = instance
    process.env.MONGO_URI = uri.slice(0, uri.lastIndexOf('/'))
  } else {
    process.env.MONGO_URI = `mongodb://${mongoConfig.ip}:${mongoConfig.port}`
  }

  // set prisma url for integration tests to point to in memory mongodb
  process.env.PRISMA_DATABASE_URL = process.env.MONGO_URI
  process.env.PRISMA_DATABASE_NAME = mongoConfig.database

  // The following is to make sure the database is clean before a test starts
  await mongoose.connect(`${process.env.MONGO_URI}/${mongoConfig.database}`)
  await mongoose.connection.db?.dropDatabase()
} 

export async function teardown() {
  await mongoose.connection.dropDatabase()
  await mongoose.connection.close()

  // Config to decided if a mongodb-memory-server instance should be used
  if (mongoConfig.memory) {
    const instance = global.__MONGOINSTANCE
    await instance.stop()
  }
}

Ab diesem Moment kannst du in deinen Integrationstests mit der Datenbank interagieren und sicherstellen, dass die Annahmen der Unit-Tests stimmen. Selbst bei umfangreichen Tests bleibt die Ausführungszeit im Sekundenbereich. Das dadurch gewonnene Feedback zur Korrektheit zentraler Datenbankfunktionen ist meines Erachtens unbezahlbar.

Wie organisierst du deine Integrationstests? Führst du sie als Teil deines TDD-Flows aus oder Remote im Rahmen der Build-Pipeline?

Lass uns Erfahrungen austauschen
call to action background image

Abonniere meinen Newsletter

Erhalte einmal im Monat Nachrichten aus den Bereichen Softwareentwicklung und Kommunikation gespikt mit Buch- und Linkempfehlungen.