
단위 테스트 할 때, 정규 표현식도 많이 쓰니 꼭 보고 오세요.
소프트웨어 개발 과정에서 가장 작은 테스트 가능 단위, 즉 개별 함수, 메소드, 클래스 등과 같은 단위들을 검증하는 과정입니다.
정확성, 변경 용이성, 문서화, 디버깅 등의 효과를 기대할 수 있습니다.
테스트를 함으로써 각 단위가 독립적으로 올바르게 작동하는지 확인할 수 있습니다.
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
// 테스트 케이스
test('renders learn react link', () => {
render(<MyComponent />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
const db = require('./db');
// 테스트 케이스
test('fetch user by id', async () => {
const user = await db.fetchUserById(1);
expect(user).toEqual({ id: 1, name: 'John Doe' });
});
const request = require('supertest');
const app = require('./app');
// 테스트 케이스
test('GET /api/user', async () => {
const response = await request(app).get('/api/user');
expect(response.status).toBe(200);
expect(response.body).toEqual({ id: 1, name: 'John Doe' });
});
단위 테스트를 작성할 때, 아래의 기준인 Right - BICEP에 따르면 더욱 효율적입니다.
이제 테스트 라이브러리를 사용해 log만큼 정확하면서 간결한 테스트 라이브러리를 써보겠습니다.
저는 외부 라이브러리를 고를 때 첫번째로 npm 다운로드 횟수와 업데이트 횟수를 보고 고릅니다. 우선은 나에게 맞는지 검토하기 전에, 이 라이브러리를 사용하는 개발자 커뮤니티를 보고 고민을 조금 낮추는 편입니다.
Jest가 약 3배 이상의 다운로드 횟수를 보이고 있습니다. 하지만 업데이트는 Mocha는 3일 전, Jest는 10달 전으로 조금 고민이 됩니다.
문법이 의외로 중요합니다. 러닝 커브가 높냐 낮냐의 차이도 개발자 경험에 큰 영향을 주기 때문입니다.
// Jest
const Person = require('./person');
describe('Person unit tests', () => {
let person;
beforeEach(() => {
person = new Person('John', 30);
});
it('Should be an adult', () => {
expect(person.isAdult()).toBe(true);
});
it('Should be a child', () => {
person.age = 12;
expect(person.isAdult()).toBe(false);
});
});
Jest는 설정이 간단하며, 테스트 러너, assertion, mocking 기능이 모두 포함되어 있어 별도의 설정 없이 바로 사용할 수 있습니다. 문법도 직관적이어서 초보자들이 쉽게 배울 수 있습니다.
// Mocha
const chai = require('chai');
const expect = chai.expect;
const Person = require('./person');
describe('Person unit tests', () => {
let person;
beforeEach(() => {
person = new Person('John', 30);
});
it('Should be an adult', () => {
expect(person.isAdult()).to.be.true;
});
it('Should be a child', () => {
person.age = 12;
expect(person.isAdult()).to.be.false;
});
});
Mocha는 Chai, Sinon과 같은 추가 라이브러리를 사용해야 하므로 설정이 복잡할 수 있습니다.
하지만 더 많은 유연성을 제공하며, 다양한 테스트 요구 사항에 맞게 커스터마이징할 수 있습니다.
여기서는 경로를 만들어주고, 현재 경로의 파일을 관리해주는 Path 클래스를 테스트합니다. Path 클래스의 다양한 메소드를 테스트하고, 각 메소드가 올바르게 동작하는지 검증합니다.
import { Path } from './index.js';
import fs from 'fs';
// jest
describe('Unix : Path 클래스 테스트', () => {
// https://www.daleseo.com/jest-before-after/
beforeAll(() => {
// 테스트용 파일 생성
fs.writeFileSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
'Hello, world!',
);
fs.writeFileSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test2.txt',
'Hello, world!',
);
fs.writeFileSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test3.txt',
'Different content',
);
});
afterAll(() => {
// 테스트용 파일 삭제
fs.unlinkSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
fs.unlinkSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test2.txt',
);
fs.unlinkSync(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test3.txt',
);
});
test('Path Class 검증', () => {
const p = new Path('/home/user/boost/camp/challenge/day8/problem.md');
expect(p.isWindows).toBe(false);
expect(p.root).toBe('/');
expect(p.base).toBe('problem.md');
expect(p.ext).toBe('.md');
expect(p.name).toBe('problem');
expect(p.absoluteString).toBe(
'/home/user/boost/camp/challenge/day8/problem.md',
);
});
test('appendComponent : 경로에 요소를 추가할 수 있어야 한다', () => {
const p = new Path('/home/user/boost/camp.txt');
p.appendComponent('New Folder');
expect(p.pathString).toBe('/home/user/boost/New Folder/camp.txt');
expect(p.absoluteString).toBe('/home/user/boost/New Folder/camp.txt');
});
test('deleteLastComponent : base를 제외한 마지막 경로 요소를 제거할 수 있어야 한다', () => {
const p = new Path('/home/user/boost/camp/challenge/day8/problem.md');
p.deleteLastComponent();
expect(p.pathString).toBe('/home/user/boost/camp/challenge/problem.md');
expect(p.absoluteString).toBe('/home/user/boost/camp/challenge/problem.md');
});
test('existFile : 파일 존재 여부를 확인할 수 있어야 한다', () => {
const p = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
expect(p.existFile).toBe(true);
});
test('fileSize : 파일 크기를 반환할 수 있어야 한다', () => {
const p1 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
expect(p1.fileSize).toBe(13);
const p3 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test3.txt',
);
expect(p3.fileSize).toBe(17);
});
test('compareFileSize : 파일 크기를 비교할 수 있어야 한다', () => {
const p1 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
const p2 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test2.txt',
);
expect(p1.compareFileSize(p2)).toBe(true);
});
test('compareFileName : 파일 이름을 비교할 수 있어야 한다', () => {
const p1 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
const p2 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
expect(p1.compareFileName(p2)).toBe(true);
});
test('compareFileContent : 파일 내용을 비교할 수 있어야 한다', () => {
const p1 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test1.txt',
);
const p2 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test2.txt',
);
const p3 = new Path(
'/Users/taeyeon/Desktop/Progamming/Coding_Test/Naver/test3.txt',
);
expect(p1.compareFileContent(p2)).toBe(true);
expect(p1.compareFileContent(p3)).toBe(false);
});
test('유효성 검사 - 예외 처리 : 특수문자가 포함된 경로는 예외를 발생시켜야 한다', () => {
expect(() => new Path('/home/user/boost/camp<.txt')).toThrow(
'경로에는 공백, 숫자, 영어, 한글, 마침표, 슬래시 및 백슬래시만 포함될 수 있습니다.',
);
expect(() => new Path('/home/user/boost|camp.txt')).toThrow(
'경로에는 공백, 숫자, 영어, 한글, 마침표, 슬래시 및 백슬래시만 포함될 수 있습니다.',
);
});
test('한글과 공백이 포함된 경로를 지원해야 한다', () => {
const p = new Path('/home/user/boost/캠프.txt');
expect(p.base).toBe('캠프.txt');
expect(p.name).toBe('캠프');
expect(p.ext).toBe('.txt');
expect(p.absoluteString).toBe('/home/user/boost/캠프.txt');
});
});
describe('Window : Path 클래스 테스트', () => {
test('Path Class 검증', () => {
const p = new Path(
'C:\\home\\user\\boost\\camp\\challenge\\day8\\problem.md',
);
expect(p.isWindows).toBe(true);
expect(p.root).toBe('C:\\');
expect(p.base).toBe('problem.md');
expect(p.ext).toBe('.md');
expect(p.name).toBe('problem');
expect(p.absoluteString).toBe(
'C:\\home\\user\\boost\\camp\\challenge\\day8\\problem.md',
);
});
});
아주 간편한 함수가 여러개 있습니다.
beforeAll : 테스트가 시작되기 전에 실행됩니다.
위 예시에서는 테스트용 파일을 생성합니다.
afterAll : 모든 테스트가 완료된 후 실행됩니다.
위 예시에서는 테스트용 파일을 삭제합니다.
beforeEach : 각 테스트 전에 실행됩니다. 필요한 경우 테스트 환경을 초기화합니다.
afterEach : 각 테스트 후에 실행됩니다. 테스트 환경을 정리합니다.
C::를 사용합니다.C:/를 사용하고, Windows에서는 \\를 사용합니다.C:\Users\User\file.txt/home/user/file.txt, C:\\Users\\User\\file.txt.(현재 디렉터리)와 ..(상위 디렉터리)를 사용합니다../file.txt, ../file.txt:를 사용하여 경로 요소를 구분하고, Windows에서는 ;를 사용합니다./usr/bin:/bin:/usr/sbin:/sbin , Windows: C:\\Windows;C:\\Program Files네트워크 경로를 나타내는 형식입니다. 일반적으로 네트워크상의 리소스에 접근할 때 사용됩니다. UNC 경로는 \\\\서버이름\\공유폴더 형식을 가집니다.
ex) \\\\server\\share\\file.txt
https://www.example.com/path/to/resourceexample.com, urn:isbn:0451450523