E2E 테스트 (with Cypress)
우아한테크코스 3주차 과제인 "점심 뭐 먹지" 과제를 하면서 처음으로 E2E 테스트에 대해서 접하게 되었다.
이를 계기로 E2E 테스트가 무엇인지, 그리고 어떻게 쓰는 것인지 간단하게 소개해보려고 한다.
E2E 테스트
프론트엔드 앱은 결국 '실제 사용자가 잘 사용할 수 있어야' 의미가 생긴다.
E2E 테스트는 최대한 실제 사용자가 앱을 사용하듯이 작성하여, 실제 사용할 때 생길 수 있는 문제를 사전에 검증할 수 있도록 한다.
실제 사용성을 그대로 테스트할 수 있는 큰 장점이 있는 대신 실제 프로덕션 앱을 개발하는 상황을 가정하자면 단위 테스트에 비해 작성하는 비용이 큰 편이다.
그만큼 앱에서 가장 핵심이 되는 기능 플로우를 잘 선정하여 해당 기능에 문제가 생기지 않는지를 검증하기 위한 장치로 활용한다.
잘 작성해둔다면 개발자 및 기획자, 디자이너, QA 등이 직접 수동으로 기능을 테스트해보아야 하는 수고를 매우 크게 덜 수 있다.
테스트 대상 범위
Cypress 소개
- E2E 테스트 뿐만 아니라 '실제 브라우저에서 동작하는 방식'을 테스트 해야 하는 모든 경우에 활용할 수 있다.
-
End-to-end tests
- 통합 테스트
- 단위 테스트
- API 테스트
- 등등
-
- 소프트웨어 테스팅은 소프트웨어의 품질을 보장하고 결함을 예방하고 수정하는 데 매우 중요한 과정이다. 특히 지속적이고 반복적이고 자주 일어나는 작업들은 가능한 자동화하고 효율적으로 수행하는 것이 좋다.
cypress는 웹애플리케이션을 테스트하기 위한 자바스크립트로 작성된 가벼운 라이브러리로, 실제 애플리케이션과 테스트 코드를 동일한 브라우저에서 실행하는 방식을 취하고 있다.
브라우저 기반의 GUI를 사용하여 테스트의 실행 상태를 확인하고 디버깅할 수 있는 다양한 편의 기능을 제공한다.
예를들어 실행된 모든 테스트 명령과 각 명령이 실행될 때의 UI 상태를 스냅샷 형태로 모두 저장해 특정 시점의 UI 상태를 눈으로 확인할 수 있다.
또한 전체 테스트 진행 과정을 동영상으로 저장하거나 테스트가 실패했을 때 자동으로 스크린샷을 남길 수 있어 테스트가 실패했을 때 원인을 파악하기가 매우 쉽다.
브라우저에서 실행되기 때문에 필요한 경우 크롬 개발자 도구를 사용해 디버깅을 할 수도 있으며, 무엇보다 자바스크립트로 작성되었기 때문에 테스트 코드 역시 사용자가 웹 페이지에서 요소를 찾는 방식과 유사한 메서드를 제공하여 큰 러닝커브 없이 빠르게 학습이 가능하다는 장점이 있다.
E2E 테스트 도구
E2E( End-to-End ) 테스트란 '시작부터 끝까지'라는 의미로, 애플리케이션이 제대로 작동하는지, 사용자 관점에서 시스템 흐름을 테스트하는 소프트웨어 테스트 방법이다.
이 테스트의 목적은 실제 생산 환경과 유사한 환경에서 시스템이 전체적인 비즈니스 목표에 충족하는지 확인하기 위해 실제 사용자 시나리오를 시뮬레이션하고 해당 구성 요소의 통합 및 데이터 무결성을 검증하는 것이다.
쉽게 말해 실제 사용자 시나리오를 모방해 사용자가 개발한 시스템을 오류나 버그없이 예상대로 작동하는지에 대한 검증이라고 보면 된다.
예를 들어, 사용자가 쇼핑몰 사이트에 접속하고, 로그인하고, 상품을 검색하고, 장바구니에 담고, 결제하고, 주문 확인하는 일련의 사용 시나리오를 테스트 한다고 이해하면 된다.
이처럼, E2E 테스트는 테스트 방법론이며, Cypress는 이 방법론을 실제로 구현하기 위한 도구인 것이다.
Cypress 기본 문법
describe()
: 테스트 코드를 묶는 가장 큰 단위. 테스트 스위트
it()
: 실제 테스트 케이스를 정의하는 함수
before()
: 테스트 스위트의 첫 번째 테스트 케이스가 실행되기 전에 한 번만 실행
after()
: 테스트 스위트의 마지막 테스트 케이스가 실행된 후에 한 번만 실행
beforeEach()
: 테스트 스위트의 각 테스트 케이스가 실행되기 전에 매번 실행됩
afterEach()
: 테스트 스위트의 각 테스트 케이스가 실행된 후에 매번 실행
Cypress 기초
사이트 접속 테스트하기
- 개발 중인 사이트를 Cypress에서 테스트하는 방법입니다.
아래 코드처럼cy.visit()
을 사용해 특정 URL로 이동할 수 있습니다.
describe('로컬 사이트 테스트 시트', () => {
it('로컬 사이트 방문', () => {
cy.visit('http://localhost:5173');
});
});
Element의 id값 혹은 class 값으로 선택하는 방법
- 웹 페이지에서 특정 요소를 선택할 때는 id, class, 태그 이름 등을 활용할 수 있습니다.
Cypress에서는cy.get()
을 사용하여 요소를 선택합니다.
cy.get('button'); // 태그 이름으로 선택
cy.get('.className'); // 클래스명으로 선택
cy.get('#idName'); // ID 값으로 선택
cy.get('[class^="button_"]'); // 특정 접두사를 가진 class 선택
예제: 버튼 클릭
cy.get('#button').click();
비동기 처리 (wait() 활용) - 매크로 시나리오
describe('무신사 사이트 테스트 시트', () => {
it('쇼핑몰 버튼 클릭', () => {
cy.visit('https://www.musinsa.com/app/'); // 무신사 방문
cy.get('[u_cat_cd="001"] > a').click();
cy.wait(1000); // 1초 대기
cy.get('[u_cat_cd="002"] > a').click();
cy.wait(1000);
cy.get('[u_cat_cd="003"] > a').click();
cy.wait(1000);
cy.get('[u_cat_cd="004"] > a').click();
});
});
입력 필드 자동화 (타이핑)
describe('네이버 테스트', () => {
it('네이버 로그인', () => {
cy.visit('https://nid.naver.com/nidlogin.login');
cy.get('#id').type('test'); // 아이디 입력
cy.get('#pw').type('123123'); // 비밀번호 입력
cy.get('#log\\.login').click(); // 로그인 버튼 클릭
});
});
Dropdown 자동 선택
- select 안
describe('무신사 사이트 테스트 시트', () => {
it('상품 메뉴 선택하기', () => {
cy.visit('https://www.musinsa.com/app/goods/3791036?loc=goods_rank');
// 상품 옵션 선택하기
cy.get('.product-detail__sc-1d13nsy-1').select('M');
cy.get('.product-detail__sc-1k1gum8-0').select('589908');
});
});
Cypress Assertion
- Cypress Assertion이란 Cypress에서 테스트의 결과가 예상한 값과 일치하는지 검증하는 방법을 말한다.
예를들어 어느 제목의 텍스트가 특정 문자열과 일치하는지 확인하는데 이용된다.
// h2태그의 text가 특정 제목인지 확인
cy.get('h2').should('have.text', '특정 제목');
// button을 클릭하고 나면 class에 active가 있어야 하는 경우
cy.get('button').click().should('have.class', 'active');
// 해당 객체가 없어야 하는 경우
cy.get('button').should('not.exist');
// 두 조건을 만족해야 하는 경우 (and)
cy.get('#header a')
.should('have.class', 'active') // 클래스명이 active 일 경우
.and('have.attr', 'href', '/users'); // href 속성 값이 /users 일경우
// 체크박스가 disabled된 경우
cy.get(':checkbox').should('be.disabled');
// input에 특정 값이 없어야 하는 경우
cy.get('input').should('not.have.value', 'US');