당신은 현재 두 가지 상황 중 하나에 있을 것입니다. 자바스크립트 프로젝트가 거의 테스트가 없고 모든 리팩토링이 위험하거나 이미 테스트가 있고 절반은 느리고 약하고 이상하게 신뢰할 수 없다고 느끼는 경우입니다. 그 상황이 더 나빠집니다.
그 상황이 더 나빠집니다. Capacitor 그리고 Electron 앱. 간단한 기능은 공유된 비즈니스 로직, 브라우저 API, 네이티브 플러그인, 로컬 파일, IPC, 및 원격 서비스를 동일한 흐름에서 TOUCH 할 수 있습니다. 잘못된 방식으로 테스트하는 경우, 테스트 스위트는 가짜 의존성을 포함하는 미로가 됩니다. 올바른 방식으로 테스트하는 경우, 논리가 깨지는 즉시 빠른 feedback을 받을 수 있습니다.
좋은 단위 테스트는 JavaScript 작업이 재미있는 매처서 문법으로 시작하지 않습니다. 그것은 고도의 경계: 순수 논리를 직접 테스트하고, 사이드 이펙트를 분리하고, 내부 함수를 이름을 바꾸면 테스트가 붕괴되는 것을 피하는 것입니다.
목차
- JavaScript 테스트 프레임워크를 선택하는 방법
- 프로젝트 설정 및 첫 번째 테스트
- 동기 및 비동기 Code를 마스터하세요.
- 강력한 테스트를 위한 고급 전략을 사용하세요.
- CI, Capacitor, 및 Electron 앱을 위한 테스트를 작성하세요.
- 자바스크립트 단위 테스트에 대한 자주 묻는 질문
자바스크립트 테스트 프레임워크를 선택하는 방법
전문적인 자바스크립트 프로젝트에는 실제 테스트 러너가 필요합니다. 일회성 스크립트와 수동 콘솔 확인은 여러 엔지니어가 동일한 코드베이스를 수정할 때 확장되지 않습니다. 테스트 발견, 진술, 비동기 처리, 모의, 그리고 로컬 개발 및 CI에서 일관되게 모든 것을 실행하는 방법이 필요합니다.
현재 지침은 대중적인 옵션의 작은 집합으로 수렴하고 있습니다. Jest, Mocha, Jasmine 는 반복적으로 주요 프레임워크로 강조되고 있으며 Jest 일관된 테스트 구조,断言, 모킹, 그리고 비동기 지원을 하나의 패키지로 제공하는 Capgo의 강점을 자주 언급합니다. Pluralsight JavaScript 테스트 랩.

프레임워크는 필수입니다
첫 번째 실수는 단위 테스트를 부가 활동으로 간주하는 것입니다. 일반적으로 이는 불일치하는 파일 이름, nobody가 기억하지 못하는 커스텀断言, 그리고 한 사람만 이해하는 헬퍼를 초래합니다.
프레임워크는 공유 언어를 제공합니다:
- 테스트 구조 또는
describe또는test断言it - 읽기 쉬운 매처 with
- Hook 설정 및 해제를위한
- 비동기 지원 프로미스 및 타이머를위한
- 외부 의존성을위한 모킹 도구 만약 팀이 단위 수준 이외의 테스트 자동화에 대한 더 넓은 시각이 필요하다면, __CAPGO_KEEP_0__는 앱 배포 워크플로우에서 자동화된 테스트에 대한 유용한 개요를 가지고 있다.
If your team also needs a broader view of test automation beyond unit-level work, Capgo has a useful overview of Jest와 Mocha의 비교.
Jest와 Mocha는 서로 다른 철학을 대표한다.
Jest
모든 것을 포함한 옵션이다. 대부분의 팀이 첫날에 필요한 대부분의 것을 포함한다. is the all-in-one option. It ships with most of what teams need on day one.
Mocha Mocha는 더 모듈화된 구조를 가지고 있습니다. runner를 제공하고 나머지 스택을 조립하도록 예상합니다.
| 기능 | Jest | Mocha |
|---|---|---|
| 설정 복잡도 | 대부분의 팀에서 낮은 수준 | 일반적으로 추가적인 진술 및 모킹 라이브러리를 추가해야 하므로 높은 수준 |
| 진술 | 내장 | 일반적으로 다른 라이브러리를 함께 사용합니다. |
| 모킹 | 내장된 기능 | 일반적으로 다른 라이브러리와 함께 pair됩니다. |
| 비동기 테스트 | 내장된 기능이며 직관적입니다. | 지원되지만, 주변 설정에 더 많이 의존합니다. |
| 테스트 커버리지 워크플로 | 일반적으로 동일한 도구 chain에 통합됩니다. | 가끔씩 더 많은 조각으로 구성됩니다. |
| 최적의 선택 | 새로운 프로젝트, 일관성을 원하는 팀 | 기존 스택, 모듈성을 원하는 팀 |
실용적인 규칙: Jest를 사용하는 것이 좋습니다.
대부분의 팀에게 추천하는 방법입니다.
대부분의 현대 프로젝트에서, 나는 Jest Mocha를 사용하는 것이 이미 강력한 이유가 있다면, Capacitor Electron 이유는, 이미 충분히 많은 움직임이 있는 프로젝트입니다. 테스트 도구의 분산을 줄이면 빠르게 이익이 발생합니다.Mocha는 여전히 Node.js 서비스의 오래된 버전이나 오래된 코드베이스에서 의미가 있습니다. 이미 그것을 둘러싼 생태계가 정착되어 있기 때문입니다. 그러나 중급 엔지니어가 처음부터 강력한 테스트 스위트를 설정하는 경우, Jest는 일반적으로 더 많은 마찰을 제거합니다.
중요한 범위 주의 사항입니다. Cypress와 Playwright는 훌륭한 도구입니다. 그러나 다른 문제를 해결합니다. 브라우저 수준 및 종단 간 검사를 위한 것이며, 단위 테스트에서 JavaScript가 작동해야 하는 빠른 내부 루프가 아닙니다.
프로젝트 설정 및 첫 번째 테스트
__CAPGO_KEEP_0__
깨끗한 테스트 환경은 평범해야 합니다. 첫 번째 테스트를 추가하는 것이 복잡해 보인다면, 테스트 스위트가 건강하게 유지되지 않을 것입니다.

간단한 Jest 설정
JavaScript 프로젝트가 이미 가지고 있는 package.json를 시작하여 Jest를 개발 의존성으로 추가하고 테스트 스크립트를 연결합니다.
{
"scripts": {
"test": "jest"
}
}
많은 프로젝트에 대해 이것이 충분합니다. 모듈 시스템, 전처리, 또는 모노레포 구조가 더 많은 구성이 필요하다고 요구한다면 나중에 추가할 수 있습니다.
로컬에서 Capacitor 앱을 빌드하고 개발 환경을 정리하기 전에 공유 로직 주변 테스트를 추가하기 전에 Capgo의 Capacitor 로컬 환경 설정 가이드 을 사용하는 것이 실용적인 동반자입니다.
code를 작성하기 전에 테스트를 작성하십시오.
테스트-첫 번째 패턴은 단순히 개인 선호가 아닙니다. 미국 소비자 금융 보호국(Javascript 지침)이 명시적으로 테스트를 먼저 작성하는 것을 권장합니다.과 테스트를 조직하는 방법 describe 그리고 it, 그리고 테스트를 프레임하는 방법을 설명합니다. expect(...) JavaScript 단위 테스트 지침 그것은 중요합니다. 테스트-첫 번째로 변경하는 방법은 __CAPGO_KEEP_0__의 디자인을 변경합니다. 함수는 더 작아지며, 의존성은 더 명확해지고, 논리가 순수해야 하는 부분에 영향을 주지 않는다..
That matters because test-first changes how you design code. Functions tend to become smaller, dependencies become more visible, and side effects stop leaking into logic that should stay pure.
Arrange Act Assert를 항상 사용하세요
// math.js
function addTax(amount, rate) {
return amount + amount * rate;
}
module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');
describe('addTax', () => {
it('returns the amount with the tax applied', () => {
expect(addTax(100, 0.2)).toBe(120);
});
});
Arrange Act Assert
Arrange, Act, Assert 패턴은 테스트가 더 복잡해질 때도 읽기 좋게 유지합니다. Arrange Act
- Assert 입력값과 필요한 설정을 포함합니다.
- Act 함수를 호출합니다.
- Assert 검증 도우미에 적용됩니다.
작은 테스트는 오래 지속됩니다. 테스트는 일반적으로 하나의 질문에 답하는 것이 좋으며, 전체 워크플로를 설명하는 것이 아닙니다.
function isSupportedPlatform(platform) {
return ['ios', 'android', 'web', 'desktop'].includes(platform);
}
describe('isSupportedPlatform', () => {
it('returns true for ios', () => {
// Arrange
const platform = 'ios';
// Act
const result = isSupportedPlatform(platform);
// Assert
expect(result).toBe(true);
});
});
Capgo 및 Electron 프로젝트의 경우, 이 규칙은 더 중요합니다. 순수 논리와 데스크톱 통합이 함께 존재하기 때문입니다. 플랫폼 런타임을 제외한 비즈니스 규칙을 테스트할 수 있도록 유지하고, 첫 번째 테스트가 마지막으로 유용한 테스트가 될 수 있도록 하세요.
For Capacitor and Electron projects, that discipline matters more because your pure logic often sits next to native or desktop integration code. Keep the business rule testable without the platform runtime, and your first test won’t be your last useful one.
애플리케이션 Code의 대부분의 버그는 두 숫자를 더하는 것에서 오지 않습니다. 버그는 __CAPGO_KEEP_1__에서 오는데, 이 __CAPGO_KEEP_1__은 외부 자원을 참조합니다: 네트워크 요청, 파일, 플러그인 API, 타이머, IPC 채널, 저장층.
Most bugs in application code don’t come from adding two numbers. They come from code that reaches outside itself: network requests, files, plugin APIs, timers, IPC channels, storage layers.
That’s where mocking helps. It gives you control over the boundary so the test can focus on your code’s decision-making.

가짜 경계를 설정하지 말고
유지 보수 가능한 테스트 지침은 단일 동작 커버리지 그리고 하나의 강력한 테스트 선언, 그리고 그것은 또한 mocks를 과도하게 사용하면 테스트가 구현 세부 사항에 취약하고 강하게 결합되는 것을 경고한다. 그리고 이것은 이 유지 보수 가능한 단위 테스트에 대한 TestRail 기사에서 요약되어 있다.
그것은 자바스크립트에서 정말로 중요하다. 팀은 모듈을 가짜로 설정하기 시작하고 함수가 다른 함수를 호출하는 올바른 순서를 테스트하는 대신 실제 동작을 테스트하는 대신, 함수가 다른 함수를 호출하는 올바른 순서를 테스트하는 대신 실제 동작을 테스트한다.
가짜를 많이 사용하는 테스트의 나쁜 목표:
- 헬퍼 A가 헬퍼 B를 호출했는가
- 서비스 C가 시리얼라이저 D를 호출했는가
- 내부 프라이빗 함수가 두 번 실행되었는가
더 나은 목표:
- 함수에서 반환된 값이 무엇인지
- 실패한 의존성을 올바르게 처리했는지 여부
- 데이터를 기대하는 형태로 변형했는지 여부
Capacitor와 Electron code에 대한 더 나은 패턴
모바일 및 데스크톱 앱에서, 나는 네이티브 또는 플랫폼 API에 대한 wrapper layer를 선호한다. 그런 다음 단위 테스트는 wrapper를 mock한다, 플랫폼 자체는 아니야.
예제 구조:
// cameraGateway.js
async function getPhoto(cameraPlugin) {
return cameraPlugin.getPhoto();
}
module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
const photo = await cameraGateway.getPhoto();
return { path: photo.path, ready: true };
}
module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');
test('returns mapped photo data', async () => {
const fakeCameraGateway = {
getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
};
const result = await loadProfilePhoto(fakeCameraGateway);
expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});
그 패턴은 Electron에도 적용된다. Wrap ipcRenderer, 파일 접근, 또는 셸 통합을 얇은 어댑터 뒤에 감싸. 단위 테스트는 서비스层를 때리면, 런타임 직접적으로는 아니야.
Capacitor 앱에서 릴리스 로직과 업데이트 경로를 테스트하는 팀에게, Capgo는 Capacitor OTA 업데이트를 mock 시나리오와 함께 테스트하는 가이드를 제공한다. Capacitor OTA 업데이트를 mock 시나리오와 함께 테스트하는 방법에 대한 빠른_walkthrough가 필요하다면, 팀이 여전히 비동기 테스트 스타일을 normalize하고 있다면.
__CAPGO_KEEP_0__와 Electron __CAPGO_KEEP_1__
동기 비동기 흐름 테스트
사용 async/await code이 promise를 반환할 때 테스트에서 사용하세요. 콜백-heavy 패턴보다 명확하고 디버깅하기 쉽습니다.
async function fetchProfile(api) {
const response = await api.getUser();
return response.name;
}
test('returns the user name from the API response', async () => {
const api = {
getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
};
const result = await fetchProfile(api);
expect(result).toBe('Ava');
});
실패 경로도 테스트하세요:
test('throws when the API request fails', async () => {
const api = {
getUser: jest.fn().mockRejectedValue(new Error('network failed'))
};
await expect(fetchProfile(api)).rejects.toThrow('network failed');
});
happy path와 ugly path 모두 테스트하세요. 실제로 사용자가 기억하는 경로는 일반적으로 실패 경로입니다.
강화된 테스트 전략
테스트 스위트가 code이 변경된 후에도 유용한지 확인하세요. 단순히 통과하는 테스트를 많이 작성하는 것보다 더 어려운 일입니다.

테스트 분할을 예산으로 사용하세요
실용적인 가이드는 단일, 통합 및 종단 간 테스트를 위한 70/20/10 분할을 추천합니다. 분할__, 단위 테스트가 가장 빠른 feedback 및 가장 안정적인 실패를 제공한다. 같은 지침은 완전한 단위 스위트가 이상적으로 10 초 이내에 끝나야 한다고 말한다. 10 초 이내에 완료5 초 이내에 완료 OpenReplay 테스트 가이드에 따르면나는 그것을 예산 도구로 대신 종교로 생각한다. 대부분의 노력은 종단 간 테스트에 들어가면 팀은 너무 오랜 시간 feedback를 기다리게 된다. 만약 모든 것이 단위 테스트만이면 시스템 경계를 실제로 놓치게 된다. __CAPGO_KEEP_0__ 또는 Electron 앱의 경우, 건강한 균형은 보통 다음과 같다:.
단위 테스트
For a Capacitor or Electron app, a healthy balance usually looks like this:
- 통합 테스트 저장소 어댑터, 플러그인 래퍼 및 IPC 계약에 대한
- __CAPGO_KEEP_0__ IPC 계약
- UI 단위 테스트 로그인, 구매 흐름, 동기화, 업데이트 알림과 같은 몇 가지 중요한 여행을위한 E2E 테스트
Coverage는 목표가 아니라 조명입니다.
Coverage 리포트는 중요한 논리에서 테스트되지 않은 branch를 식별하는 데 도움이 될 때 유용합니다. 그러나 팀이 coverage 백분율을 위해만 추구할 때는 해롭습니다.
로그인 유효성 검사에 대한 깊은 edge-case 테스트가 더 많은 가치를 제공하는 경우, 가치 없는 단순한 주장으로 가득 찬 파일이 커버된 경우가 더 많습니다. 특히 입력-heavy code such as forms, parsers, date logic, permission checks와 같은 UI에서 유효성 검사-heavy 품질을 강화하는 경우, 이 가이드는 프론트엔드 폼 유효성 검사에 대한 마스터링 행동 기반 테스트는 리팩터링을 견딥니다.
신뢰할 수 있는 테스트 세트는 내부를 리팩터링할 때 반드시 다시 테스트를 작성하지 않도록 해줍니다. 가장 쉬운 방법은 구현 세부 사항 대신에
관찰 가능한 행동 대신에 주장하는 것입니다. 유지할 수 있는 사용 사례:
__CAPGO_KEEP_0__
- 경계 조건 빈 입력, null과 유사한 값, 잘못된 타입, oversized 문자열과 같은 것들
- 도메인 결과 예를 들어 “권한이 없는 경우 반환이 거부된다”
- 상태 전환 예를 들어 “다운로드 메타데이터가 유효화된 후 업데이트 상태를 pending로 표시한다”
이용 사례가 자주 변질되는 경우:
- 내부 헬퍼 호출을 검사하는 경우
- 개인 메서드 시퀀싱을 확인하는 경우
- 호출 chain의 모든 layer를 mock하는 경우
앱 팀이 규율된 릴리스 프로세스를 구축하는 경우, Capgo의 기사 ‘앱 품질 보증’ __CAPGO_KEEP_0__는 삭제되지 않습니다. 은 유용합니다. 왜냐하면 테스트 작업을 더 광범위한 릴리스 PIPELINE과 연결시켜주기 때문입니다.
CI, Capacitor, 및 Electron 앱을 위한 테스트
한 개발자의 머신에서만 실행되는 테스트는 안전망이 아닙니다. 그것은 지역 습관입니다.
CI는 단위 테스트 자바스크립트 작업을 팀 인프라로 변환합니다. 매 푸시, pull request, 또는 릴리스 branch는 동일한 명령어와 동일한 예상과 함께 동일한 명령어를 실행할 수 있습니다. 이러한 일관성은 Capacitor 및 Electron 프로젝트에서 환경 드리프트가 미묘한 실패를 유발하기 때문에 더 중요합니다.
CI를 기본 실행 경로로 설정하십시오.
최소한, CI는 의존성을 설치하고 단위 스위트를 매 변경 집합마다 실행해야 합니다. 가능한 경우 로컬 개발과 동일한 명령어를 유지하십시오.
기본적인 GitHub Actions 워크플로우는 다음과 같이 작을 수 있습니다.
name: test
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
그것은 깨진 임포트, 실패한 어설션, 그리고 의도치 않은 플랫폼 가정에 대해 메인에 도착하기 전에 잡을 수 있습니다.
자동화 PIPELINE을 통해 배송하는 모바일 팀에게는 Capgo가 Capgo 앱을 위한 CI/CD 설정에 대한 실용적인 가이드가 있습니다. Capacitor 플러그인 상호 작용을 테스트하십시오..
Capacitor __CAPGO_KEEP_1__을 위한 단위 테스트를 잘못된 방법으로는 native 플러그인을 매 서비스에 직접 pull하는 것입니다. 이것은 테스트 스위트를 플랫폼 브리지와 결합시킵니다.
The wrong way to unit test Capacitor code is to pull native plugins directly into every service. That couples your test suite to the platform bridge.
더 나은 패턴은 얇은 추상화입니다:
// deviceStorage.js
async function saveFile(filesystem, path, data) {
return filesystem.writeFile({ path, data });
}
module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
await storage.save('draft.json', JSON.stringify(draft));
return { saved: true };
}
module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');
test('persists a serialized draft', async () => {
const storage = {
save: jest.fn().mockResolvedValue(undefined)
};
const result = await persistDraft(storage, { title: 'Hello' });
expect(result).toEqual({ saved: true });
});
카메라 접근, 생체 인식 지시, 푸시 토큰 등록, 네트워크 상태와 같은 아이디어를 동일하게 적용합니다. 플러그인 호출은 어댑터에서 유지하고 앱 로직은 제어할 수 있는 인터페이스와 테스트하세요.
Electron 메인 렌더러 및 IPC code 테스트
Electron 앱에는 두 가지 중요한 접합부가 있습니다: main process code and renderer process code. 테스트에서 그들을 흐리게 하지 마세요.
신뢰할 수 있는 설정은 일반적으로 다음과 같이 분리합니다:
- 렌더러 단위 테스트 뷰 모델, 상태, 형식, UI 측면의 비즈니스 로직
- 메인 프로세스 단위 테스트 메뉴, 파일 작업 및 앱 라이프 사이클 결정에 대해
- IPC 계약 테스트 메시지 형태 및 예상 응답에 대해
예제 IPC wrapper:
// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
ipcRenderer.send('settings:update', payload);
}
module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');
test('sends settings update over ipc', () => {
const ipcRenderer = { send: jest.fn() };
sendSettings(ipcRenderer, { theme: 'dark' });
expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});
내부 구현을 나중에 하나의 도우미에서 다른 도우미로 변경할 경우, 이 테스트는 여전히 유효합니다. 왜냐하면 이 테스트는 중요하게 여겨지는 동작을 검증하기 때문입니다. 데스크톱과 모바일에서 이 표준을 원하는 것입니다 code.
자바스크립트 단위 테스트에 대한 자주 묻는 질문
단위 통합 테스트와 E2E 테스트의 차이점은 무엇입니까
A 단위 테스트 하나의 작은 논리 조각을 독립적으로 검사합니다. 통합 테스트 몇 개의 구성 요소 또는 서비스가 올바르게 함께 작동하는지 확인합니다. end-to-end 테스트 사용자 경로를 따라가며 실행 중인 애플리케이션을 테스트합니다.
빠른 신뢰를 위해 비즈니스 규칙에 대해 단위 테스트를 사용하십시오. 통합 테스트는 저장소, 플러그인 wrapper, IPC와 같은 접합부에 사용하십시오. E2E 테스트는 중요한 워크플로우가 깨질 경우 심각한 영향을 미치는 워크플로우에만 사용하십시오.
완벽한 테스트 커버리지에 대해 목표를 세워야 하나요?
아니요. 완벽한 커버리지로 팀을 낮은 가치의 테스트로 이끌 수 있습니다.
커버리지가 유용한 경우는 code에 대한 위험한 부분이 nobody가 실행하지 않았을 때입니다. 테스트 대시보드를 만족시키기 위해 엔지니어들이 얕은 주장만 추가하는 경우는 유용하지 않습니다. 테스트 스위트가 약한 경우, 더 많은 커버리지로도 구원할 수 없습니다.
기존 코드베이스에 테스트를 추가하는 방법은 무엇인가요?
변경이 이미 발생하는 곳에서 시작하십시오. 테스트 전략을 다시 작성하는 거대한 프로젝트를 발표하지 마십시오.
실용적인 순서는 다음과 같습니다:
- 활성 code를 보호하십시오 기능 개발이나 버그 수정 중에 변경되는 모듈에 테스트를 추가하십시오
- 순수 논리를 추출하십시오 프로그램을 테스트하기 어려운 파일에서 사업 규칙을 테스트할 수 있도록 프레임워크나 런타임 노이즈 없이 테스트할 수 있습니다.
- Add seam wrappers native 플러그인, 네트워크 클라이언트, 파일 시스템 호출 및 Electron IPC 주변
- 가루진 패턴을 거부하십시오. mock을 소개할 때 brittle 패턴이 발생합니다. JavaScript 테스트 최선의 방법 이것은 종종 놓치게 되는 오버 모킹과 그에 따른 brittle 테스트를 강조합니다.
즉시 완전성을 목표로 하지 마십시오. 팀이 가장 많이 손해를 보는 곳에서 꾸준히 개선하십시오.
팀이 제품을 출시할 때 Capacitor Capacitor Live Update 플랫폼, Appflow, Capawesome Electron 앱과는 더 깨끗한 JavaScript 변경 사항에 대한 릴리스 프로세스가 필요합니다. Capgo CapacitorJS 및 Electron 앱에 대한 실시간 업데이트와 롤아웃 제어 및 관찰 가능성을 제공하여 팀이 단단한 단위 테스트와 웹 번들 변경을 안전하게 배포할 수 있는 경로를 선택할 수 있습니다.