설치, 테스트 작성, 디버깅, CI/CD 통합 및 모범 사례를 다루는 강력한 엔드 투 엔드 테스트 프레임워크인 Cypress에 대한 포괄적인 가이드입니다.
Cypress: 웹 애플리케이션을 위한 최고의 엔드 투 엔드 테스트 가이드
오늘날 급변하는 웹 개발 환경에서 웹 애플리케이션의 품질과 신뢰성을 보장하는 것은 매우 중요합니다. 엔드 투 엔드(E2E) 테스트는 사용자의 관점에서 애플리케이션의 모든 구성 요소가 원활하게 함께 작동하는지 확인하는 데 중요한 역할을 합니다. Cypress는 개발자 친화적인 경험, 강력한 기능 및 뛰어난 성능을 제공하여 최고의 E2E 테스트 프레임워크로 부상했습니다. 이 포괄적인 가이드에서는 Cypress를 시작하고 웹 애플리케이션을 효과적으로 테스트하는 데 필요한 모든 것을 안내합니다.
Cypress란 무엇인가요?
Cypress는 최신 웹을 위해 구축된 차세대 프런트 엔드 테스트 도구입니다. 브라우저에서 테스트를 실행하는 기존 테스트 프레임워크와 달리 Cypress는 브라우저에서 직접 작동하여 애플리케이션의 동작에 대한 비교할 수 없는 제어 및 가시성을 제공합니다. 빠르고 안정적이며 사용하기 쉽도록 설계되어 전 세계 개발자와 QA 엔지니어 사이에서 인기 있는 선택입니다. Cypress는 JavaScript로 작성되었으며 브라우저 내에서 실행되므로 성능이 매우 뛰어나고 애플리케이션의 내부 요소에 대한 탁월한 액세스를 제공합니다.
Cypress 사용의 주요 이점
- 개발자 친화적: Cypress는 깨끗하고 직관적인 API를 제공하여 테스트를 쉽게 작성하고 디버깅할 수 있도록 합니다.
- 시간 여행: Cypress는 각 테스트 명령 동안 애플리케이션 상태의 스냅샷을 찍어 언제든지 시간을 거슬러 올라가 정확히 어떤 일이 발생했는지 확인할 수 있습니다.
- 실시간 다시 로드: Cypress는 테스트를 변경하면 자동으로 다시 로드하여 즉각적인 피드백을 제공합니다.
- 자동 대기: Cypress는 작업 수행 전에 요소가 표시되거나 상호 작용 가능하게 될 때까지 자동으로 대기하므로 명시적 대기가 필요하지 않습니다.
- 네트워크 제어: Cypress를 사용하면 네트워크 요청 및 응답을 스텁하여 다양한 시나리오를 시뮬레이션하고 애플리케이션의 오류 처리를 테스트할 수 있습니다.
- 디버깅 가능성: Cypress는 강력한 디버거와 자세한 오류 메시지를 포함하여 훌륭한 디버깅 도구를 제공합니다.
- 크로스 브라우저 테스트: Cypress는 Chrome, Firefox, Edge 및 Electron을 포함한 여러 브라우저를 지원합니다.
- 헤드리스 테스트: CI/CD 환경에서 더 빠른 실행을 위해 헤드리스 모드로 테스트를 실행합니다.
- 내장된 어설션: Cypress는 애플리케이션의 예상 동작을 확인하기 위한 풍부한 내장 어설션 세트를 제공합니다.
설치 및 설정
Cypress를 시작하는 것은 간단합니다. 설치 방법은 다음과 같습니다.
- 사전 요구 사항: 시스템에 Node.js 및 npm(Node Package Manager)이 설치되어 있는지 확인합니다. 공식 Node.js 웹사이트에서 다운로드할 수 있습니다.
- Cypress 설치: 터미널 또는 명령 프롬프트를 열고 프로젝트 디렉토리로 이동하여 다음 명령을 실행합니다.
- Cypress 열기: 설치가 완료되면 다음을 실행하여 Cypress 테스트 러너를 열 수 있습니다.
npm install cypress --save-dev
npx cypress open
이 명령은 테스트를 실행하고 디버깅하기 위한 그래픽 인터페이스를 제공하는 Cypress 테스트 러너를 시작합니다.
첫 번째 Cypress 테스트 작성
웹사이트의 홈 페이지가 제대로 로드되는지 확인하는 간단한 테스트를 만들어 보겠습니다. 프로젝트의 `cypress/e2e` 디렉토리에 `example.cy.js`라는 새 파일을 만듭니다.
// cypress/e2e/example.cy.js
describe('My First Test', () => {
it('Visits the Kitchen Sink', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
cy.url().should('include', '/commands/actions')
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
이 테스트를 분석해 보겠습니다.
- `describe()`: 관련 테스트 모음인 테스트 모음을 정의합니다.
- `it()`: 테스트 모음 내에서 개별 테스트 케이스를 정의합니다.
- `cy.visit()`: 지정된 URL로 이동합니다.
- `cy.contains()`: 지정된 텍스트를 포함하는 요소를 찾습니다.
- `.click()`: 선택한 요소를 클릭합니다.
- `cy.url()`: 페이지의 현재 URL을 가져옵니다.
- `.should()`: 애플리케이션의 상태에 대한 어설션을 만듭니다.
- `cy.get()`: CSS 선택자를 사용하여 요소를 선택합니다.
- `.type()`: 선택한 요소에 텍스트를 입력합니다.
- `.should('have.value', 'fake@email.com')`: 요소의 값이 'fake@email.com'과 같은지 어설션합니다.
Cypress 테스트 러너에서 이 테스트를 실행하여 실제로 작동하는지 확인하십시오. 브라우저가 Cypress Kitchen Sink 웹사이트로 이동하여 "type" 링크를 클릭하고 URL을 확인하는 것을 볼 수 있습니다.
Cypress 명령
Cypress는 애플리케이션과 상호 작용하기 위한 광범위한 명령을 제공합니다. 다음은 가장 일반적으로 사용되는 명령 중 일부입니다.
- `cy.visit(url)`: 지정된 URL로 이동합니다.
- `cy.get(selector)`: CSS 선택자를 사용하여 요소를 선택합니다.
- `cy.contains(content)`: 지정된 텍스트를 포함하는 요소를 선택합니다.
- `cy.click()`: 선택한 요소를 클릭합니다.
- `cy.type(text)`: 선택한 요소에 텍스트를 입력합니다.
- `cy.clear()`: 입력 또는 텍스트 영역 요소의 내용을 지웁니다.
- `cy.submit()`: 양식을 제출합니다.
- `cy.check()`: 확인란 또는 라디오 버튼을 선택합니다.
- `cy.uncheck()`: 확인란 선택을 취소합니다.
- `cy.select(value)`: 드롭다운에서 옵션을 선택합니다.
- `cy.scrollTo(position)`: 페이지를 지정된 위치로 스크롤합니다.
- `cy.trigger(event)`: 선택한 요소에서 DOM 이벤트를 트리거합니다.
- `cy.request(url, options)`: 지정된 URL로 HTTP 요청을 보냅니다.
- `cy.intercept(route, handler)`: 지정된 경로와 일치하는 HTTP 요청을 가로챕니다.
- `cy.wait(time)`: 지정된 시간 동안 대기합니다.
- `cy.reload()`: 현재 페이지를 다시 로드합니다.
- `cy.go(direction)`: 브라우저 기록에서 이전 페이지 또는 다음 페이지로 이동합니다.
- `cy.url()`: 페이지의 현재 URL을 가져옵니다.
- `cy.title()`: 페이지의 제목을 가져옵니다.
- `cy.window()`: window 객체를 가져옵니다.
- `cy.document()`: document 객체를 가져옵니다.
- `cy.viewport(width, height)`: 뷰포트 크기를 설정합니다.
이것은 Cypress에서 사용할 수 있는 많은 명령 중 일부일 뿐입니다. 전체 명령 목록과 해당 옵션은 Cypress 설명서를 참조하십시오.
Cypress의 어설션
어설션은 애플리케이션의 예상 동작을 확인하는 데 사용됩니다. Cypress는 요소의 상태, URL, 제목 등을 확인하는 데 사용할 수 있는 풍부한 내장 어설션 세트를 제공합니다. 어설션은 `.should()` 메서드를 사용하여 Cypress 명령 뒤에 연결됩니다.
다음은 몇 가지 일반적인 어설션 예입니다.
- `.should('be.visible')`: 요소가 표시되는지 어설션합니다.
- `.should('not.be.visible')`: 요소가 표시되지 않는지 어설션합니다.
- `.should('be.enabled')`: 요소가 활성화되어 있는지 어설션합니다.
- `.should('be.disabled')`: 요소가 비활성화되어 있는지 어설션합니다.
- `.should('have.text', 'expected text')`: 요소에 지정된 텍스트가 있는지 어설션합니다.
- `.should('contain', 'expected text')`: 요소에 지정된 텍스트가 포함되어 있는지 어설션합니다.
- `.should('have.value', 'expected value')`: 요소에 지정된 값이 있는지 어설션합니다.
- `.should('have.class', 'expected class')`: 요소에 지정된 클래스가 있는지 어설션합니다.
- `.should('have.attr', 'attribute name', 'expected value')`: 요소에 지정된 속성 및 값이 있는지 어설션합니다.
- `.should('have.css', 'css property', 'expected value')`: 요소에 지정된 CSS 속성 및 값이 있는지 어설션합니다.
- `.should('have.length', expected length)`: 요소에 지정된 길이(예: 목록의 요소 수)가 있는지 어설션합니다.
특정 요구 사항에 맞게 사용자 지정 어설션을 만들 수도 있습니다.
Cypress 테스트 작성 모범 사례
모범 사례를 따르면 더 유지 관리 가능하고 안정적이며 효율적인 Cypress 테스트를 작성할 수 있습니다. 다음은 몇 가지 권장 사항입니다.
- 명확하고 간결한 테스트 작성: 각 테스트는 특정 기능 또는 시나리오에 집중해야 합니다. 이해하고 유지 관리하기 어려운 지나치게 복잡한 테스트를 작성하지 마십시오.
- 의미 있는 테스트 이름 사용: 테스트하는 내용을 명확하게 나타내는 설명적인 이름을 테스트에 지정합니다.
- 값 하드코딩 방지: 시간이 지남에 따라 변경될 수 있는 값을 저장하려면 변수 또는 구성 파일을 사용합니다.
- 사용자 지정 명령 사용: 재사용 가능한 로직을 캡슐화하고 테스트를 더 읽기 쉽게 만들려면 사용자 지정 명령을 만듭니다.
- 테스트 격리: 각 테스트는 다른 테스트와 독립적이어야 합니다. 이전 테스트의 애플리케이션 상태에 의존하지 마십시오.
- 테스트 후 정리: 각 테스트 후에 애플리케이션 상태를 재설정하여 후속 테스트가 깨끗한 상태에서 시작되도록 합니다.
- 데이터 속성 사용: 테스트에서 요소를 선택하려면 데이터 속성(예: `data-testid`)을 사용합니다. 데이터 속성은 CSS 클래스 또는 ID보다 변경될 가능성이 적으므로 테스트가 UI 변경에 더 탄력적입니다.
- 명시적 대기 방지: Cypress는 요소가 표시되거나 상호 작용 가능하게 될 때까지 자동으로 대기합니다. 명시적 대기(예: `cy.wait()`)는 절대적으로 필요한 경우에만 사용하십시오.
- 사용자 흐름 테스트: 개별 구성 요소보다는 사용자 흐름 테스트에 집중합니다. 이렇게 하면 사용자의 관점에서 애플리케이션이 제대로 작동하는지 확인할 수 있습니다.
- 테스트를 정기적으로 실행: Cypress 테스트를 CI/CD 파이프라인에 통합하고 정기적으로 실행하여 개발 프로세스 초기에 버그를 포착합니다.
고급 Cypress 기술
스텁 및 모킹
Cypress를 사용하면 네트워크 요청 및 응답을 스텁하여 다양한 시나리오를 시뮬레이션하고 애플리케이션의 오류 처리를 테스트할 수 있습니다. 이는 외부 API 또는 서비스에 의존하는 기능을 테스트하는 데 특히 유용합니다.
네트워크 요청을 스텁하려면 `cy.intercept()` 명령을 사용할 수 있습니다. 예를 들어, 아래 코드는 `/api/users`에 대한 GET 요청을 스텁하고 모의 응답을 반환합니다.
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]
}).as('getUsers')
그런 다음 `cy.wait('@getUsers')`를 사용하여 가로챈 요청을 기다리고 애플리케이션이 모의 응답을 올바르게 처리하는지 확인할 수 있습니다.
로컬 스토리지 및 쿠키 사용
Cypress는 로컬 스토리지 및 쿠키와 상호 작용하기 위한 명령을 제공합니다. 이러한 명령을 사용하여 테스트에서 로컬 스토리지 및 쿠키를 설정, 가져오기 및 지울 수 있습니다.
로컬 스토리지 항목을 설정하려면 `cy.window()` 명령을 사용하여 window 객체에 액세스한 다음 `localStorage.setItem()` 메서드를 사용할 수 있습니다. 예를 들어:
cy.window().then((win) => {
win.localStorage.setItem('myKey', 'myValue')
})
로컬 스토리지 항목을 가져오려면 `cy.window()` 명령을 사용한 다음 `localStorage.getItem()` 메서드를 사용할 수 있습니다. 예를 들어:
cy.window().then((win) => {
const value = win.localStorage.getItem('myKey')
expect(value).to.equal('myValue')
})
쿠키를 설정하려면 `cy.setCookie()` 명령을 사용할 수 있습니다. 예를 들어:
cy.setCookie('myCookie', 'myCookieValue')
쿠키를 가져오려면 `cy.getCookie()` 명령을 사용할 수 있습니다. 예를 들어:
cy.getCookie('myCookie').should('have.property', 'value', 'myCookieValue')
파일 업로드 처리
Cypress는 테스트에서 파일 업로드를 단순화하는 `cypress-file-upload`라는 플러그인을 제공합니다. 플러그인을 설치하려면 다음 명령을 실행합니다.
npm install -D cypress-file-upload
그런 다음 `cypress/support/commands.js` 파일에 다음 줄을 추가합니다.
import 'cypress-file-upload';
그런 다음 `cy.uploadFile()` 명령을 사용하여 파일을 업로드할 수 있습니다. 예를 들어:
cy.get('input[type="file"]').attachFile('example.txt')
IFrames 사용
IFrames 테스트는 까다로울 수 있지만 Cypress는 IFrame과 상호 작용하는 방법을 제공합니다. `cy.frameLoaded()` 명령을 사용하여 IFrame이 로드될 때까지 기다린 다음 `cy.iframe()` 명령을 사용하여 IFrame의 document 객체를 가져올 수 있습니다.
cy.frameLoaded('#myIframe')
cy.iframe('#myIframe').find('button').click()
Cypress 및 CI/CD(지속적인 통합/지속적인 배포)
애플리케이션의 품질을 보장하려면 Cypress를 CI/CD 파이프라인에 통합하는 것이 필수적입니다. CI/CD 환경에서 헤드리스 모드로 Cypress 테스트를 실행할 수 있습니다. 방법은 다음과 같습니다.
- Cypress 설치: Cypress가 프로젝트의 종속성으로 설치되어 있는지 확인합니다.
- CI/CD 구성: 각 빌드 후 Cypress 테스트를 실행하도록 CI/CD 파이프라인을 구성합니다.
- 헤드리스로 Cypress 실행: `cypress run` 명령을 사용하여 헤드리스 모드에서 Cypress 테스트를 실행합니다.
예제 CI/CD 구성(GitHub Actions 사용):
name: Cypress Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Cypress run
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
이 구성은 코드가 `main` 분기로 푸시되거나 `main` 분기에 대해 풀 요청이 생성될 때마다 Cypress 테스트를 실행합니다. `cypress-io/github-action` 작업은 GitHub Actions에서 Cypress 테스트를 실행하는 프로세스를 단순화합니다.
Cypress 테스트 디버깅
Cypress는 테스트에서 문제를 식별하고 해결하는 데 도움이 되는 훌륭한 디버깅 도구를 제공합니다. Cypress 테스트 디버깅에 대한 몇 가지 팁은 다음과 같습니다.
- Cypress 테스트 러너 사용: Cypress 테스트 러너는 테스트를 실행하고 디버깅하기 위한 시각적 인터페이스를 제공합니다. 한 번에 하나의 명령으로 테스트를 단계별로 실행하고, 애플리케이션의 상태를 검사하고, 자세한 오류 메시지를 볼 수 있습니다.
- `cy.pause()` 명령 사용: `cy.pause()` 명령은 테스트 실행을 일시 중지하고 브라우저의 개발자 도구에서 애플리케이션의 상태를 검사할 수 있도록 합니다.
- `cy.debug()` 명령 사용: `cy.debug()` 명령은 선택한 요소를 콘솔에 출력하여 해당 속성 및 특성을 검사할 수 있도록 합니다.
- 브라우저의 개발자 도구 사용: 브라우저의 개발자 도구는 DOM, 네트워크 요청 및 콘솔 로그를 포함하여 애플리케이션에 대한 풍부한 정보를 제공합니다.
- 오류 메시지를 주의 깊게 읽으십시오: Cypress는 오류의 원인을 식별하는 데 도움이 되는 자세한 오류 메시지를 제공합니다. 오류 메시지와 스택 추적에 주의하십시오.
Cypress 대 다른 테스트 프레임워크
Cypress는 강력한 엔드 투 엔드 테스트 프레임워크이지만 다른 인기 있는 옵션과 비교하는 방법을 이해하는 것이 중요합니다. 다음은 간략한 개요입니다.
- Selenium: Selenium은 널리 사용되는 자동화 테스트 프레임워크입니다. 유연하고 여러 언어를 지원하지만 설정하고 유지 관리하기가 복잡할 수 있습니다. Cypress는 특히 JavaScript 기반 애플리케이션의 경우 더 간단하고 개발자 친화적인 경험을 제공합니다.
- Puppeteer: Puppeteer는 헤드리스 Chrome 또는 Chromium을 제어하기 위한 고급 API를 제공하는 Node 라이브러리입니다. 스크래핑 및 브라우저 작업 자동화에 적합하지만 엔드 투 엔드 테스트의 경우 Cypress에 비해 더 많은 수동 구성이 필요할 수 있습니다.
- Playwright: Playwright는 Microsoft에서 개발한 또 다른 크로스 브라우저 자동화 프레임워크입니다. Puppeteer와 유사하지만 더 광범위한 브라우저 지원을 제공합니다. Cypress에는 고유한 시간 여행 디버거와 더 통합된 테스트 환경이 있습니다.
프레임워크 선택은 프로젝트의 특정 요구 사항에 따라 다릅니다. Cypress는 빠르고 안정적이며 개발자 친화적인 엔드 투 엔드 테스트가 필요한 최신 웹 애플리케이션에 적합한 선택입니다.
실제 Cypress 사용 예
Cypress를 사용하여 다양한 유형의 웹 애플리케이션을 테스트할 수 있는 몇 가지 실제 예를 살펴보겠습니다.
전자 상거래 애플리케이션 테스트
Cypress를 사용하여 다음과 같은 전자 상거래 애플리케이션에서 다양한 사용자 흐름을 테스트할 수 있습니다.
- 제품 검색
- 장바구니에 제품 추가
- 결제 및 주문
- 계정 설정 관리
사용자가 장바구니에 제품을 성공적으로 추가할 수 있는지 확인하는 Cypress 테스트의 예는 다음과 같습니다.
it('Adds a product to the cart', () => {
cy.visit('/products')
cy.get('.product-card').first().find('button').click()
cy.get('.cart-count').should('have.text', '1')
})
소셜 미디어 애플리케이션 테스트
Cypress를 사용하여 다음과 같은 소셜 미디어 애플리케이션에서 사용자 상호 작용을 테스트할 수 있습니다.
- 새 게시물 만들기
- 게시물 좋아요
- 게시물에 댓글 달기
- 다른 사용자 팔로우
사용자가 새 게시물을 성공적으로 만들 수 있는지 확인하는 Cypress 테스트의 예는 다음과 같습니다.
it('Creates a new post', () => {
cy.visit('/profile')
cy.get('#new-post-textarea').type('Hello, world!')
cy.get('#submit-post-button').click()
cy.get('.post').first().should('contain', 'Hello, world!')
})
뱅킹 애플리케이션 테스트
뱅킹 애플리케이션의 경우 Cypress를 사용하여 다음과 같은 중요한 기능을 테스트할 수 있습니다.
- 안전하게 로그인
- 계정 잔액 확인
- 자금 이체
- 수혜자 관리
자금 이체를 확인하는 테스트는 다음과 같을 수 있습니다(보안을 위해 적절한 스터빙 포함).
it('Transfers funds successfully', () => {
cy.visit('/transfer')
cy.get('#recipient-account').type('1234567890')
cy.get('#amount').type('100')
cy.intercept('POST', '/api/transfer', { statusCode: 200, body: { success: true } }).as('transfer')
cy.get('#transfer-button').click()
cy.wait('@transfer')
cy.get('.success-message').should('be.visible')
})
결론
Cypress는 웹 애플리케이션의 품질과 신뢰성을 보장하는 데 도움이 되는 강력하고 다재다능한 엔드 투 엔드 테스트 프레임워크입니다. 개발자 친화적인 API, 강력한 기능 및 뛰어난 성능은 전 세계 개발자와 QA 엔지니어 사이에서 인기 있는 선택입니다. 이 가이드에 설명된 모범 사례를 따르면 개발 프로세스 초기에 버그를 포착하고 사용자에게 고품질 소프트웨어를 제공하는 데 도움이 되는 효과적인 Cypress 테스트를 작성할 수 있습니다.
웹 애플리케이션이 계속 발전함에 따라 엔드 투 엔드 테스트의 중요성은 더욱 커질 것입니다. Cypress를 수용하고 개발 워크플로에 통합하면 더욱 강력하고 안정적이며 사용자 친화적인 웹 환경을 구축할 수 있습니다.