"node:fs" 테스트 하기

Nextjs 를 사용하게 되면서 SSG(static site generators) 와 SSR(server side rendering) 을 사용하게 되었습니다.

덕분에 CSR(client side rendering) 의 단점인 SEO 를 해소할 수 있게 되었습니다.

SSG(static site generators) 와 SSR(server side rendering) 을 사용하게 되면, node 모듈들을 사용할 수 있습니다.

이번 포스팅은 node:fs 를 사용하는 코드의 유닛 테스트 방법에 대해 정리합니다.


Jest 에서 안내하는 built-in modules 테스트


Jest 공식문서에 의하면, built-in modules 를 테스트하기 위해 몇가지 사전준비가 필요합니다.

  • node_modules 와 인접한 경로에 mocks 폴더 만들기
  • 테스트할 built-in module 과 동일한 이름의 파일(fs.js) 을 mocks 하위에 만들기
  • fs.js 파일 구현하기
    • jest.createMockFromModule('fs') 를 호출하여 mock 적용하기
    • fs 의 메시드 중, 테스트 대상이 사용하는 모든 메서드에 mock 구현
  • 유닛 테스트 파일에서 jest.mock('fs') 로 mock 적용하기

위 과정을 모두 구현할 수도 있지만, 좀 더 편리한 방법을 찾아본 결과 mock-fs 라는 라이브러리를 찾게 되었습니다.

mock-fs 는 Jest 에서 안내하는 "node:fs" 테스트 준비 과정을 제공합니다.


mock-fs 설치하기

만약 Typescript 를 사용한다면, @types/mock-fs 모듈도 함께 설치합니다.

Javascript 사용 시
yarn add -D mock-fs
Typescript 사용 시
yarn add -D mock-fs @types/mock-fs

node:fs 테스크 코드 작성하기


mock-fs 를 사용하게 되면 아래의 2가지 작업이 필요합니다.

  • jest.beforeEach(): mock-fs 를 사용한 file system mockup
  • jest.afterEach(): mock-fs 해제

먼저 테스트 준비를 위한 mockup 을 구현하면 다음과 같습니다.

import mock from 'mock-fs';
 
describe('mock-fs 를 사용한 "node:fs" 테스트', () => {
    beforeEach(() => {
        mock({
            '경로1': {
                '하위_경로1': {
                    '파일_1.mdx': '파일 내용 mockup',
                    '파일_2.mdx': '파일 내용 mockup',
                },
            },
            '경로2/경로3': {
                '하위_경로2': {
                    // 빈 폴더
                },
            },
        });
    });
});

이제 node:fs 는 mockup 에서 정의한 mock file system 을 사용하게 됩니다.

import fs from 'node:fs/promises';
import mock from 'mock-fs';
 
describe('mock-fs 를 사용한 "node:fs" 테스트', () => {
    beforeEach(() => {
        mock({
            '경로1': {
                '하위_경로1': {
                    '파일_1.mdx': '파일 내용 mockup',
                    '파일_2.mdx': '파일 내용 mockup',
                },
            },
            '경로2/경로3': {
                '하위_경로2': {
                    // 빈 폴더
                },
            },
        });
    });
 
    it('"node:fs" 를 사용하여 파일을 가져올 수 있다.', async () => {
        const fileNameList = await fs.readdir('경로1/하위_경로1');
 
        expect(fileNameList).toEqual([
            '파일_1.mdx',
            '파일_2.mdx',
        ]);
    });
});

마지막으로 mock-fs 를 해제할 수 있도록 jest.afterEach() 를 작성하면 "node:fs" 유닛 테스트는 작성완료 됩니다.

import fs from 'node:fs/promises';
import mock from 'mock-fs';
 
describe('mock-fs 를 사용한 "node:fs" 테스트', () => {
    beforeEach(() => {
        mock({
            '경로1': {
                '하위_경로1': {
                    '파일_1.mdx': '파일 내용 mockup',
                    '파일_2.mdx': '파일 내용 mockup',
                },
            },
            '경로2/경로3': {
                '하위_경로2': {
                    // 빈 폴더
                },
            },
        });
    });
 
    afterEach(mock.restore);
 
    it('"node:fs" 를 사용하여 파일을 가져올 수 있다.', async () => {
        const fileNameList = await fs.readdir('경로1/하위_경로1');
 
        expect(fileNameList).toEqual([
            '파일_1.mdx',
            '파일_2.mdx',
        ]);
    });
});

마치며

이번 포스팅에서는 built-in modules 중 "fs" 를 테스트하는 방법에 대해 정리해 보았습니다.

"fs" 가 아닌 다른 module 에 대한 테스트를 한다면, 결국은 Jest 공식문서에서 안내하는 mockup 방법도 사용해 보아야 할 것 같습니다.