Testcontainers for Node.js 시작하기

Testcontainers for Node.js 시작하기

이 가이드에서는 Testcontainers for Node.js를 이용해 실제 PostgreSQL 인스턴스로 Node.js 애플리케이션을 만들고 데이터베이스 상호작용을 테스트하는 방법을 배워요.

출처: 문서

본문

이 가이드를 통해 다음 내용을 배울 수 있어요.

  • PostgreSQL에서 고객을 저장하고 조회하는 Node.js 애플리케이션 만들기
  • Testcontainers와 Jest로 통합 테스트 작성하기
  • Docker 컨테이너의 실제 PostgreSQL 데이터베이스에 대해 테스트 실행하기

사전 준비 (Prerequisites)

  • Node.js 18 이상
  • npm
  • Testcontainers가 지원하는 Docker 환경

참고: Testcontainers가 처음이라면 Testcontainers 개요를 방문해 알아보는 걸 권장해요.

Node.js 프로젝트 만들기

새 Node.js 프로젝트를 만들어요.

$ npm init -y

pg, jest, @testcontainers/postgresql을 의존성으로 추가해요.

$ npm install pg --save
$ npm install jest @testcontainers/postgresql --save-dev

고객 리포지토리 구현하기

PostgreSQL에서 고객을 관리하는 함수를 가진 src/customer-repository.js를 만들어요.

async function createCustomerTable(client) {
  const sql =
    "CREATE TABLE IF NOT EXISTS customers (id INT NOT NULL, name VARCHAR NOT NULL, PRIMARY KEY (id))";
  await client.query(sql);
}

async function createCustomer(client, customer) {
  const sql = "INSERT INTO customers (id, name) VALUES($1, $2)";
  await client.query(sql, [customer.id, customer.name]);
}

async function getCustomers(client) {
  const sql = "SELECT * FROM customers";
  const result = await client.query(sql);
  return result.rows;
}

module.exports = { createCustomerTable, createCustomer, getCustomers };

이 모듈은 세 가지 함수를 제공해요.

  • createCustomerTable()은 customers 테이블이 없으면 만들어요.
  • createCustomer()는 고객 레코드를 삽입해요.
  • getCustomers()는 모든 고객 레코드를 가져와요.

Testcontainers로 테스트 작성하기

테스트와 함께 src/customer-repository.test.js를 만들어요.

const { Client } = require("pg");
const { PostgreSqlContainer } = require("@testcontainers/postgresql");
const {
  createCustomerTable,
  createCustomer,
  getCustomers,
} = require("./customer-repository");

describe("Customer Repository", () => {
  jest.setTimeout(60000);

  let postgresContainer;
  let postgresClient;

  beforeAll(async () => {
    postgresContainer = await new PostgreSqlContainer().start();

    postgresClient = new Client({
      connectionString: postgresContainer.getConnectionUri(),
    });
    await postgresClient.connect();

    await createCustomerTable(postgresClient);
  });

  afterAll(async () => {
    await postgresClient.end();
    await postgresContainer.stop();
  });

  it("should create and return multiple customers", async () => {
    const customer1 = { id: 1, name: "John Doe" };
    const customer2 = { id: 2, name: "Jane Doe" };

    await createCustomer(postgresClient, customer1);
    await createCustomer(postgresClient, customer2);

    const customers = await getCustomers(postgresClient);

    expect(customers).toEqual([customer1, customer2]);
  });
});

테스트가 하는 일을 살펴보면,

  • beforeAll 블록이 PostgreSqlContainer로 실제 PostgreSQL 컨테이너를 시작해요.
  • 그런 다음 컨테이너에 연결된 pg 클라이언트를 만들고 customers 테이블을 설정해요.
  • afterAll 블록이 클라이언트 연결을 닫고 컨테이너를 중지해요.
  • 테스트는 고객 두 명을 삽입하고 모든 고객을 가져와 결과가 일치하는지 단언해요.
  • 테스트 타임아웃을 60초로 설정해서 첫 실행(Docker 이미지를 받아야 할 때)에 컨테이너가 시작될 시간을 확보해요.

테스트 실행과 다음 단계

package.json에 아직 없다면 테스트 스크립트를 추가해요.

{
  "scripts": {
    "test": "jest"
  }
}

그런 다음 테스트를 실행해요.

$ npm test

다음과 같은 출력이 보여야 해요.

PASS src/customer-repository.test.js
  Customer Repository
    ✓ should create and return multiple customers (5 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total

Testcontainers가 내부적으로 무엇을 하는지 — 어떤 컨테이너를 시작하고, 어떤 버전을 사용하는지 — 보려면 DEBUG 환경 변수를 설정해요.

$ DEBUG=testcontainers* npm test

요약 (Summary)

Testcontainers for Node.js 라이브러리는 목(mock) 대신 프로덕션에서 쓰는 것과 같은 종류의 데이터베이스(Postgres)를 사용해 통합 테스트를 작성할 수 있게 도와줘요. 목을 쓰지 않고 실제 서비스와 대화하기 때문에, 코드를 리팩터링해도 애플리케이션이 예상대로 동작하는지 검증할 수 있답니다.

PostgreSQL 외에도 Testcontainers는 많은 SQL 데이터베이스, NoSQL 데이터베이스, 메시징 큐 등을 위한 전용 모듈을 제공해요.

Testcontainers에 대해 더 알아보고 싶다면 Testcontainers 개요를 방문해요.

더 읽어보기 (Further reading)

  • Testcontainers for Node.js 문서

더 알아보기 (Learn more)