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

프레임워크는 필수입니다
팀이 첫 번째 실수를犯하는 이유는 단위 테스트를 부가 활동으로 간주하는 것입니다. 일반적으로 이는 불일치하는 파일 이름, nobody가 기억하지 못하는 커스텀断言, 그리고 한 사람만 이해하는 헬퍼를 초래합니다.
프레임워크는 공유 언어를 제공합니다:
- 테스트 구조 또는
describe또는test또는it - 또는 또는
- 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
모든 것을 포함한 옵션이다. 대부분의 팀이 첫날에 필요한 대부분의 것을 포함한다. Mocha
Mocha Mocha는 더 모듈화된 테스트 프레임워크입니다. runner를 제공하고 나머지 스택을 조립하는 것을 기대합니다.
| 기능 | Jest | Mocha |
|---|---|---|
| 설정 복잡도 | 대부분의 팀에서 낮은 수준 | 일반적으로 추가적인 assertion 및 mocking 라이브러리를 추가해야 하므로 더 높은 수준 |
| 확인 | 내장 | 일반적으로 다른 라이브러리와 pair로 사용 |
| 모킹 | 내장된 기능 | 일반적으로 다른 라이브러리와 함께 pair됩니다. |
| 비동기 테스트 | 내장된 기능이며 직관적입니다. | 지원되지만, 주변 설정에 더 많이 의존합니다. |
| 테스트 커버리지 워크플로 | 일반적으로 동일한 도구 chain에 통합됩니다. | 많이 조각조각되어 있습니다. |
| 최적의 선택 | 새로운 프로젝트, 일관성을 원하는 팀 | 기존 스택, 모듈성을 원하는 팀 |
실용적인 규칙: Jest를 사용하는 것이 좋습니다. 만약 팀이 assertion 라이브러리와 mocking 라이브러리를 runner와 pair하는 것을 물어본다면.
대부분의 팀에게 추천하는 방법입니다.
대부분의 현대 프로젝트에서, 나는 Jest 을 선택합니다. Mocha를 사용하는 이유가 이미 강력한 이유가 있다면, Mocha를 계속 사용하는 것이 좋습니다. Capacitor 또는 Electron이유는, 이미 충분히 많은 부분이 움직이고 있기 때문입니다. 테스트 도구의 sprawl을 줄이면 빠르게 이익을 얻을 수 있습니다.
Mocha는 여전히 Node.js 서비스의 오래된 버전이나 오래된 코드베이스에서 의미가 있습니다. 이미 Mocha의 생태계가 정착된 경우입니다. 하지만 중급 엔지니어가 처음부터 강력한 테스트 스위트를 설정하는 경우, Jest는 더 많은 마찰을 줄이기 때문에 일반적으로 더 좋습니다.
중요한 범위 주의 사항입니다. Cypress와 Playwright는 훌륭한 도구입니다. 하지만 다른 문제를 해결합니다. 브라우저 수준과 종단 간 검사를 위한 것이고, 단위 테스트에서 JavaScript가 살아야 하는 빠른 내부 루프에서는 아닙니다.
프로젝트 설정과 첫 번째 테스트
깨끗한 테스트 환경은 평범해야 합니다. 첫 번째 테스트를 추가하는 것이 복잡해 보인다면, 테스트 스위트가 건강하게 유지되지 않을 것입니다.

간단한 Jest 설정
JavaScript 프로젝트가 이미 가지고 있는 package.json그 다음에 Jest를 개발 의존성으로 추가하고 테스트 스크립트를 연결합니다.
{
"scripts": {
"test": "jest"
}
}
많은 프로젝트에는 이것이 충분합니다. 모듈 시스템, 전처리, 또는 모노레포 구조가 더 많은 구성이 필요하다고 요구한다면, 나중에 추가할 수 있습니다.
로컬 Capacitor 앱을 빌드하고 개발 환경을 정리하고 싶다면, Capgo의 로컬 Capacitor 환경 설정 가이드 테스트를 작성하기 전에 __CAPGO_KEEP_0__
Write the test before the code
테스트를 먼저 작성하도록 권장합니다. writing the test first과 테스트를 조직하는 방법 describe 그리고 it, 테스트에 대한 프레임을 설정하는 expect(...) 의 JavaScript 단위 테스트 지침.
그것은 중요합니다. 테스트-첫 번째로 변경하는 방법은 code의 설계를 변경합니다. 함수는 더 작아지며, 의존성은 더 명확해지고, 논리적으로 유지되어야 하는 부분에 영향을 미치는 부수 효과가 사라집니다.
다음은 최소한의 예입니다.
// 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 유효성 검사 도우미에 적용됩니다.
작은 테스트는 오래 지속됩니다. 테스트는 일반적으로 하나의 질문에 답하는 것이 좋으며, 전체 워크플로를 설명하는 것이 아닙니다.
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__가 외부 자원을 호출하는 경우에만 버그가 발생합니다.
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를 선호한다. 그런 다음 unit tests는 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, 파일 접근, 또는 셸 통합을 얇은 어댑터 뒤에 숨긴다. Unit tests는 서비스 layer에 접근한다, 런타임 직접 접근하지 않아.
Capacitor 앱에서 릴리스 로직과 업데이트 경로를 테스트하는 팀에게, Capgo는 Capacitor OTA 업데이트를 mock 시나리오와 함께 테스트하는 관련된 가이드를 가지고 있다. Capacitor OTA 업데이트를 mock 시나리오와 함께 테스트하는 방법에 대한 빠른_walkthrough가 필요하다면, 팀이 여전히 비동기 테스트 스타일을 normalize하고 있다면.
팀이 여전히 비동기 테스트 스타일을 normalize하고 있다면 __CAPGO_KEEP_0__ OTA 업데이트를 mock 시나리오와 함께 테스트하는 방법에 대한 빠른 walkthrough가 필요하다.
동기식 흐름 테스트하기
사용 async/await code이 promise를 반환할 때 테스트에서 사용하세요. 콜백이 많은 패턴보다 명확하고 디버깅하기도 더 쉽습니다.
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');
});
__CAPGO_KEEP_0__이 실패할 때도 테스트하세요:
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');
});
행복한 경로와 불행한 경로 모두 테스트하세요. 실제 운영 환경에서 불행한 경로는 사용자가 기억하는 경로입니다.
강력한 테스트 전략
테스트 스위트가 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__ Electron
- E2E 테스트 로그인, 구매 흐름, 동기화, 업데이트 알림과 같은 몇 가지 중요한 여행을위한 테스트
보장은 등대, 목표는 아님
보장은 유용할 때가 있지만, 중요한 논리 branch를 테스트하지 않은 곳을 발견하는 데 도움이 되면 유용합니다. 그러나 팀이 보장률을 위해만 쫓기 시작하면 해로울 수 있습니다.
주의 깊게 edge-case 테스트를 수행하는 로그인 검증기는 가치가 더 높으며, 가치가 더 높은 UI에 대한 검증-heavy 품질을 강화하는 팀이면 특히如此. code의 input-heavy 요소, 예를 들어, 양식, 파서, 날짜 논리, 권한 검사와 같은 경우입니다. 만약 팀이 UI에 대한 검증-heavy 품질을 강화하고자 한다면, 이 가이드는 프론트엔드 양식 검증을 마스터하는 것에 대한 가이드
행동-첫 번째 테스트는 리팩토링을 견딤
신뢰할 수 있는 테스트 스위트는 내부를 리팩토링할 때 반드시 다시 테스트를 작성하지 않도록 해줍니다. 가장 쉬운 방법은 구현 세부 사항 대신에 관찰 가능한 행동 보장하는 것입니다.
유지할 수 있는 사용 사례:
- 경계 조건 빈 입력, null과 같은 값, 잘못된 타입, oversized 문자열과 같은 것들
- 도메인 결과 예를 들어 “권한이 없는 경우 반환이 거부된다”
- 상태 전환 예를 들어 “다운로드 메타데이터가 검증된 후 업데이트 상태를 pending로 표시한다”
가끔씩 변하는 사용 사례:
- 내부 헬퍼 호출을 검사하는 것
- 사용자 정의 메서드의 순서를 확인하는 것
- 호출 chain의 모든 layer를 mock하는 것
disciplined 릴리즈 프로세스를 구축하는 앱 팀에게 Capgo의 기사 앱 품질 보증 CI는 테스트 작업을 더 광범위한 릴리스 PIPELINE과 연결하기 때문에 유용합니다.
CI, Capacitor, 및 Electron 앱을 위한 테스트
한 개발자의 머신에서만 실행되는 테스트는 안전망이 아니라 지역 습관입니다.
CI는 단위 테스트 자바 스크립트 작업을 팀 인프라로 변환합니다. 모든 푸시, pull 요청 또는 릴리스 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
이것만으로는 깨진 임포트, 실패하는 진술, 그리고 의도치 않은 플랫폼 가정에 대해 메인에 도착하기 전에 잡을 수 있습니다.
Capgo 앱을 위한 CI/CD 설정에 대한 실용적인 지침이 있는 Capgo 팀은 자동화 PIPELINE을 통해 모바일을 배송합니다. Capacitor 플러그인 상호 작용을 테스트하는 방법.
Capacitor __CAPGO_KEEP_1__을 위한 단위 테스트하는 올바른 방법은 플랫폼 브리지를 통해 native 플러그인을 모든 서비스에 직접 pull하는 것이 아닙니다. 이로 인해 테스트 스위트가 플랫폼 브리지를 의존하게 됩니다.
Capacitor code을 위한 단위 테스트하는 올바른 방법은 플랫폼 브리지를 통해 native 플러그인을 모든 서비스에 직접 pull하는 것이 아닙니다. 이로 인해 테스트 스위트가 플랫폼 브리지를 의존하게 됩니다.
더 나은 패턴은 얇은 추상화입니다:
// 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 main renderer 및 IPC code 테스트
Electron 앱에는 두 가지 중요한 접합부가 있습니다: main process code 그리고 renderer process code. 테스트에서 그들을 흐리게 하지 마십시오.
신뢰할 수 있는 설정은 일반적으로 분리합니다:
- 렌더러 단위 테스트 뷰 모델, 상태, 형식, UI 측면의 비즈니스 로직
- main process 단위 테스트 메뉴, 파일 작업 및 앱 라이프 사이클 결정에 대해
- 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 단위 테스트 하나의 작은 논리 조각을 독립적으로 검사합니다. 통합 테스트 몇 개의 컴포넌트 또는 서비스가 올바르게 작동하는지 확인합니다. 단위 테스트 사용자 경로를 따라 실제 애플리케이션을 실행하는 것을 시뮬레이션합니다.
빠른 신뢰를 위해 비즈니스 규칙에 대한 단위 테스트를 사용하십시오. 통합 테스트를 사용하여 저장소, 플러그인 래퍼, IPC와 같은 접합부를 테스트하십시오. E2E 테스트는 워크플로우가 깨질 경우 심각한 영향을 미치는 워크플로우에 대해 가볍게 사용하십시오.
완벽한 테스트 커버리지에 도달해야 하나요
아니요. 완벽한 커버리지로 팀을 저가 테스트로 밀어넣지 마십시오.
커버리지가 유용한 경우는 code가 위험한 부분을 드러내는 경우입니다. 그러나 엔지니어들이 대시보드를 만족시키기 위해 얕은 주장만 추가하는 경우는 유용하지 않습니다. 만약 테스트 스위트가 약한 경우, 더 많은 커버리지로 그것을 구원할 수 없습니다.
기존 코드베이스에 테스트를 추가하는 방법은 무엇인가요
변경이 이미 발생하는 곳에서 시작하십시오. 테스트 전략의 대규모 리뉴얼을 발표하지 마십시오.
실용적인 순서가 다음과 같습니다.
- 활발한 code를 보호하십시오 기능 작업 또는 버그 수정 중에 접근하는 모듈에 테스트를 추가하십시오
- 순수 논리를 추출하십시오 프로그램의 어려운 테스트 파일에서 사업 규칙이 프레임워크나 런타임 노이즈 없이 테스트될 수 있도록 하기 위해
- Add seam wrappers 자연 플러그인, 네트워크 클라이언트, 파일 시스템 호출 및 Electron IPC 주변
- 가루진 패턴을 거부하십시오 mock을 도입할 때 JavaScript 테스트의 최고 권장 사항 이것은 특히 오버 모킹과 그에 따른 가루진 테스트를 자주 놓친 문제를 강조하기 때문에 유용합니다.
목표는 즉시 완전성을 얻는 것이 아닙니다. 팀이 가장 많이 손해를 보는 곳에서 꾸준히 개선하는 것입니다.
팀이 Capacitor Capacitor 또는 앱과는 더 깨끗한 JavaScript 변경 사항에 대한 릴리스 프로세스가 필요합니다. Capgo CapacitorJS와 Electron 앱에 대한 실시간 업데이트, 롤아웃 제어 및 관찰성 기능을 제공하여 팀이 단단한 단위 테스트와 웹 번들 변경을 안전하게 배포할 수 있는 경로를 선택할 수 있습니다.