최근 테스트에 대해 궁금하기도 하고 필요성을 느껴 배워보기로 했다.
혼자 공부하자니 좀 어려운거 같고 해서 강의를 찾아보니 인프런에 강병진님이 올려주신 '2시간으로 끝내는 프론트엔드 테스트 기본기' 강의가 있어 보고 공부하게 되었다.
2시간으로 끝내는 프론트엔드 테스트 기본기 강의 | 강병진 - 인프런
강병진 | 테스트코드! 어디서부터 시작해야할지 막막한 분들을 위해 준비했어요. 테스트 작성부터, 자동화를 통한 배포까지 한번에!, 테스트 코드를 작성하고 싶은 프론트엔드 개발자를 위한 강
www.inflearn.com
들어보니 크게 어려운건 없는 것 같지만 배운 내용을 정리 해보려고 한다.
테스트 코드란?
우선 테스트 코드가 뭔지 알아야 한다.
간단하게 보면
- 테스팅의 주요 목적은 코드가 올바르게 작동하는지 확인하는 것
- 다양한 조건 및 입력에서 React 컴포넌트가 예상대로 동작하는지 확인
정도 이다.
장점으로는
- 코드 파악이 용이함
- 새로운 개발자가 왔을 때 온보딩이 수월
- 기획자와의 소통의 도구로 사용 가능
등이 있다.
유닛테스트, 통합테스트, E2E테스트
크게 3가지로 테스트가 있다
유닛테스트는 가장 작은 단위의 테스트로
로그인을 예로 들면 인풋이나 버튼들이 잘 렌더링 되는지, 이메일 인풋의 값이 잘 변경되는지, 회원가입을 한다면 비밀번호가 설정한 규칙에 잘 맞는지 등이 있다.
통합테스트는 다양한 컴포넌트, 모듈, 함수들이 잘 연결되는지
로그인으로 예를 들면 로그인 버튼을 클릭하고, 로그인 성공 시 원하는 화면으로 잘 redirect되는지, 로그인 실패하면 별도로 선언한 Modal이 잘 보여지는지 등이 있다.
E2E테스트는
실제 사용자인 것 처럼, 유닛+통합테스트 정도이다.
유닛테스트, 통합테스트는 보통 Jest로 진행하고 E2E테스트는 cypress로 진행한다고 한다.
프론트엔드는 보통 E2E테스트를 진행한다고 한다.
cypress
우선 사용하려면 다운부터 받아줘야 한다.
npm install --save-dev cypress
이후 package.json에
"cypress": "npx cypress open"
를 추가해준다.
그리고 cypress -> e2e폴더 안에 작성해주면 된다.
또 cypress.config.js에
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
baseUrl: "http://localhost:5173",
},
});
이런식으로 적어줘야 하는데 강의에서는 너무 당연한건지 그냥 넘어가서 똑같이 따라해도 작동이 안되서 끙끙 거렸다..
작성방식
describe("로그인 화면", () => {
it("사용자는 아이디와 비밀번호를 사용해 로그인", () => {
// given -로그인 페이지에 접근한다
// when - 아이디와 비밀번호를 입력하고 로그인 버튼 클릭
// then - 로그인에 성공하고 메인화면으로 이동한다
});
});
기본적으로 jest와 비슷하지만 cypress는 test()를 사용 못한다.
제이쿼리처럼 .wrap .modal 이런식으로 잡아도 괜찮지만
<Input
id="passwordInput"
data-cy="passwordInput"
type="password"
placeholder="비밀번호를 입력해주세요"
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setPa
이런식으로 data-cy="이름" 을 추가해서 사용하는걸 추천한다고 한다.
describe("로그인 화면", () => {
it("사용자는 아이디와 비밀번호를 사용해 로그인", () => {
// given -로그인 페이지에 접근한다
cy.visit("/login");
cy.get("[data-cy=emailInput]").as("emailInput");
cy.get("[data-cy=passwordInput]").as("passwordInput");
// when - 아이디와 비밀번호를 입력하고 로그인 버튼 클릭
// then - 로그인에 성공하고 메인화면으로 이동한다
});
});
위에 만들었던걸 이런식으로 잡아서 as로 이름까지 붙여준다.
그리고 인풋을 가져왔으니 그 인풋에 값을 입력해주려면
cy.get("@emailInput").type("test@test.com");
cy.get("@passwordInput").type("1234qwer");
cy.get("@emailInput").invoke("val").should("eq", "test@test.com");
이런식으로 하게 되는데
cy.get("@emailInput"):
이전에 별칭으로 지정한 emailInput 요소를 가져온다.
invoke("val"):
Query 메서드인 val()을 호출해서 입력 필드의 값을 가져온다.
should("eq", "test@test.com"):
입력 필드의 값이 "test@test.com"과 같은지 확인한다.
이런식으로 흘러간다고 보면 된다.
cy.get("[data-cy=loginButton]").should("exist").click();
// then - 로그인에 성공하고 메인화면으로 이동한다
cy.url().should("include", "/");
이후 이렇게 로그인 버튼을 가져와 해당 요소가 dom에 존재하는지 확인 후 클릭을 해준다.
cy.url():
현재 브라우저의 URL을 가져온다
should("include", "/"):
현재 URL이 “/“를 포함하고 있는지 확인한다. 만약 포함하고 있지 않으면 테스트가 실패한다.
cypress에서 HTTP request mocking
사용하기 위해 따로 다운받거나 할 필요는 없다.
intercept를 사용해 가로채면 된다.
cy.intercept({
method: "POST",
url: "/user/login",
}).as("login");
이런식으로 작성해주면 된다.
만약 body도 추가한다면
cy.intercept({
method: "POST",
url: "https://naver.com/login",
body: {
email: "test@test.com",
password: "1234qwer"
}
}).as("login");
이런식으로 된다.
만약 get이라면
cy.intercept(
{
method: "GET",
url: "/restaurant/food-type",
},
[
{
id: 1,
name: "피자",
icon: "https://kr.object.ncloudstorage.com/icons/ic-pizza.png",
},
{
id: 2,
name: "동남아",
icon: "https://kr.object.ncloudstorage.com/icons/ic-asian.png",
},
...
]
);
위처럼 값을 넣어줘야 한다.
그런데 너무 길어지게 되면 보기도 힘들고 하니
e2e폴더를 보면 fixture라고 있는데 그 파일에 json 파일을 생성해 넣어주면 된다.
cy.intercept(
{
method: "GET",
url: "/restaurant/food-type/1",
},
{
fixture: "restaurant-list.json",
}
);
그럼 위처럼 깔끔하게 가능하다.
cypress에서 TypeScript 사용하기
npm install --save-dev @types/cypress
패키지를 설치 후 tsconfig.json에서
{
...
"types": ["cypress"],
"include": ["src", "cypress/e2e/2-order/order-cy.ts", "**/*.ts"],
// 여기서 `order-cy.ts`를 명시적으로 넣어줬지만 `**/*.ts`만 추가해도 됨
...
}
추가를 해주면 된다.
cypress에서 공용 컴포넌트 테스트
describe("template spec", () => {
it("passes", () => {
cy.visit("/");
cy.get("[data-cy=deliveryBtn]").should("be.visible").as("deliveryBtn");
cy.get("[data-cy=pickupBtn]").should("be.visible").as("pickupBtn");
cy.get("@deliveryBtn").click();
cy.url().should("include", "/food-type");
});
});
이런식으로 코드를 작성 했는데 이는 처음 시작 위치를 / 로 하고
두개 있는 버튼들을 다 가져와준 뒤
.should("be.visible")를 사용해 화면에 보이는지 검사를 해준다.
이후 버튼을 클릭해 잘 이동했는지 검사한다.
jest? cypress?
마지막으로 이 둘을 보면
사실 뭘 쓰는지 정답은 팀 컨벤션을 따르는게 정답이긴 하다.
둘이 같이 사용하지도 못한다.
jest를 아무리 잘 작성했어도 cypress를 설치하고 나면 제대로 동작하지 않는다.
만약 이제 막 도입하는거라면 cypress를 추천한다고 한다.