프로그래밍 언어/NODE JS

테스트 커버리지

· 코딩마이데이

유닛 테스트를 작성하다 보면, 전체 코드 중에서 어떤 부분이 테스트되고 어떤 부분이 테스트되지 않는지 궁금합니다. 어떤 부분이 테스트되지 않는지를 알아야 나중에 그 부분의 테스트 코드를 작성할 수 있습니다. 전체 코드 중에서 테스트되고 있는 코드의 비율과 테스트되고 있지 않은 코드의 위치를 알려주는 jest의 기능이 있습니다. 바로 커버리지(coverage) 기능입니다.

커버리지 기능을 사용하기 위해 package.json에 jest 설정을 입력합니다.

{
  "name": "nodebird",
  "version": "0.0.1",
  "description": "익스프레스로 만드는 SNS 서비스",
  "main": "app.js",
  "scripts": {
    "start": "nodemon app",
    "test": "jest",
    "coverage": "jest --coverage"
  },
  "author": "cherry",
  "license": "MIT",
  "dependencies": {
    "bcrypt": "^6.0.0",
    "cookie-parser": "^1.4.7",
    "dotenv": "^17.2.3",
    "express": "^5.1.0",
    "express-session": "^1.18.2",
    "morgan": "^1.10.1",
    "multer": "^2.0.2",
    "mysql2": "^3.15.1",
    "nunjucks": "^3.2.4",
    "passport": "^0.7.0",
    "passport-kakao": "^1.0.1",
    "passport-local": "^1.0.0",
    "sequelize": "^6.37.7",
    "sequelize-cli": "^6.6.3"
  },
  "devDependencies": {
    "jest": "^24.9.0",
    "nodemon": "^3.1.10"
  }
}

 

jest 명령어 뒤에 --coverage 옵션을 붙이면 jest가 테스트 커버리지를 분석합니다.

$ npm run coverage

> nodebird@0.0.1 coverage
> jest --coverage

(node:2036) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.    
(Use `node --trace-deprecation ...` to show where the warning was created)
(node:2544) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
 PASS  routes/middlewares.test.js (7.592s)
 PASS  controllers/user.test.js (10.972s)
  ● Console

    console.error controllers/user.js:13
      테스트용 에러

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |       84 |      100 |       60 |       84 |                   |
 controllers     |      100 |      100 |      100 |      100 |                   |
  user.js        |      100 |      100 |      100 |      100 |                   |
 models          |    33.33 |      100 |        0 |    33.33 |                   |
  user.js        |    33.33 |      100 |        0 |    33.33 |        5,44,45,50 |
 routes          |      100 |      100 |      100 |      100 |                   |
  middlewares.js |      100 |      100 |      100 |      100 |                   |
-----------------|----------|----------|----------|----------|-------------------|

Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   0 total
Time:        24.083s
Ran all test suites.

 

테스트 결과가 출력되고, 추가적으로 표가 하나 더 출력됩니다. 표의 열을 살펴보면, 각각 File(파일과 폴더 이름), % Stmts(구문 비율), % Branch(if문 등의 분기점 비율), % Funcs(함수 비율), % Lines(코드 줄 수 비율), Uncovered Line #s(커버되지 않은 줄 위치)입니다. 퍼센티지가 높을수록 많은 코드가 테스트되었다는 뜻입니다.

표를 보면, 전체 파일(All files) 중에서는 83.33%의 구문과 83.33%의 분기점, 60%의 함수, 83.33%의 코드 줄이 커버되었음을 알 수 있습니다. 여기서는 명시적으로 테스트하고 require한 코드만 커버리지 분석이 된다는 점에 주의해야 합니다. All files라 하더라도 현재 controllers/user.js, models/user.js, routes/middlewares.js만 포함되어 있습니다. 따라서 테스트 커버리지가 100%라 하더라도 실제로 모든 코드를 테스트한 것은 아닐 수 있습니다.

models/user.js에서는 33.33%의 구문과 100%의 분기점, 0%의 함수, 33.33%의 코드 줄이 커버되었음을 보여줍니다. 이 줄들을 아래로 표시해보았습니다. 또한 5, 41, 42, 47번째 줄은 테스트되지 않았다는 것을 보여줍니다.

코드에서 굵게 표시해봤습니다.

 

models/users.js

const Sequelize = require("sequelize");

module.exports = class User extends Sequelize.Model {
  static init(sequelize) {
    return super.init(
      {
        email: {
          type: Sequelize.STRING(40),
          allowNull: true,
          unique: true,
        },
        nick: {
          type: Sequelize.STRING(15),
          allowNull: false,
        },
        password: {
          type: Sequelize.STRING(100),
          allowNull: true,
        },
        provider: {
          type: Sequelize.STRING(10),
          allowNull: false,
          defaultValue: "local",
        },
        snsId: {
          type: Sequelize.STRING(30),
          allowNull: true,
        },
      },
      {
        sequelize,
        timestamps: true,
        underscored: false,
        modelName: "User",
        tableName: "users",
        paranoid: true,
        charset: "utf8",
        collate: "utf8_general_ci",
      }
    );
  }

  static associate(db) {
    db.User.hasMany(db.Post);
    db.User.belongsToMany(db.User, {
      foreignKey: "followingId",
      as: "Followers",
      through: "Follow",
    });
    db.User.belongsToMany(db.User, {
      foreignKey: "followerId",
      as: "Followings",
      through: "Follow",
    });
  }
};

 

5, 41, 42, 47번째 줄에는 함수 호출이 위치하고 있습니다. 이 부분은 테스트를 하나도  작성하지 않았으므로 % Funcs가 0%로 나오는 것입니다. 테스트 커버리지를 올리기 위해 테스트를 작성해 봅시다.

const Sequelize = require("sequelize");
const User = require("./user");
const config = require("../config/config")["test"];
const sequelize = new Sequelize(
  config.database,
  config.username,
  config.password,
  config
);

describe("User 모델", () => {
  test("static init 메서드 호출", () => {
    expect(User.init(sequelize)).toBe(User);
  });
  test("static associate 메서드 호출", () => {
    const db = {
      User: {
        hasMany: jest.fn(),
        belongsToMany: jest.fn(),
      },
      Post: {},
    };
    User.associate(db);
    expect(db.User.hasMany).toHaveBeenCalledWith(db.Post);
    expect(db.User.belongsToMany).toHaveBeenCalledTimes(2);
  });
});

 

각각 init과 associate 메서드가 제대로 호출되는지 테스트해봤습니다. db 객체는 모킹했습니다. 테스트를 수헹하면 성공합니다.

$ npm test

> nodebird@0.0.1 test
> jest

 

테스트 커버리지도 살펴봅시다. 커버리지 표 부분만 확인해보겠습니다.

$ npm run coverage

-----------------|----------|----------|----------|----------|-------------------|
File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------------|----------|----------|----------|----------|-------------------|
All files        |       84 |      100 |      100 |       84 |                   |
 controllers     |      100 |      100 |      100 |      100 |                   |
  user.js        |      100 |      100 |      100 |      100 |                   |
 models          |      100 |      100 |      100 |      100 |                   |
  user.js        |      100 |      100 |      100 |      100 |                   |
 routes          |      100 |      100 |      100 |      100 |                   |
  middlewares.js |      100 |      100 |      100 |      100 |                   |
-----------------|----------|----------|----------|----------|-------------------|

 

테스트 커버리지가 대폭 올라간 것을 볼 수 있습니다. 현재 테스트 커버리지가 100%이지만 모든 코드가 테스트되고 있는 상황은 아닙니다. 따라서 테스트 커버리지를 높이는 것에 너무 집착하기 보다는 필요한 부분 위주로 올바르게 테스트하는 것이 좋습니다.

'프로그래밍 언어 > NODE JS' 카테고리의 다른 글

ws 모듈로 웹 소켓 사용하기  (0) 2026.01.11
웹 소캣 이해하기  (0) 2026.01.08
유닛 테스트(3)  (0) 2025.12.23
유닛 테스트(2)  (0) 2025.12.20
유닛 테스트  (0) 2025.12.16