6 분 소요

Cypress

Frontend Test

테스트의 종류

  • e2e
  • integration
  • unit
  • static

End to End (e2e)

실제 유저가 앱 내 행동(클릭 등)과 같이 동작하게 하고
그 일련의 function들이 정확하게 돌아가는지 verify하는 테스트

ex) cypress, testcafe, nightwatch

Integration

여러 unit들이 잘 상호 작용하여 동작하는지 확인하는 테스트

  • store에 연결된 component 테스트 혹은 생성자/리듀서 테스트 등..

Unit

하나의 unit (function)이 각각 독립적으로 잘 동작하는지 확인하는 테스트

ex) jest, chai, mocha, jasmine, karma … (js, ts 환경에서 테스트 가능)

ex) DOM: react-testing-library, Enzyme .. (가상돔 제공으로 렌더된 컴포넌트 테스트 가능)

  • 하나의 function이 정상적으로 동작했는지는 알 수 있지만, 그 function이 왜 동작했는지 언제 동작했는지 등 정상적인 플로우인지는 확인할 수 없다.

Static

코드 작성 시 타입 혹은 타이포 에러를 확인하는 테스트

ex) eslint, typescript ..

static → e2e로 갈수록

  • speed : 느려짐.
    • e2e로 갈수록 실행하는 코드가 늘어나기 때문
  • cost : 비용 많아짐.
    • CI 환경에서 더 느려질 수도 있다. (테스트를 언제 진행하느냐에 따라 다르지만)
    • 엔지니어가 테스트 코드를 작성하고 유지 관리하는 비용도 늘어난다.

사실 e2e보다 신뢰성, 정확성이 높은 것이 실제 사용자가 사용해보도록 하고 버그 리포팅을 받는 것

⇒ 너무 비용이 비싸고 오래 걸린다.

하지만,

사용 방식과 유사하게 테스트들이 resemble되게 코드를 작성하면 신뢰성을 가져갈 수 있다.

Why 테스트?

테스트의 장점이 무엇 이길래 테스트, 테스트할까.
테스트는 장점만 있을까?

테스트 장점

  • 자신감, 확신, 신용, 신뢰성 보장
    개발자에게 확신을 줘서 개발 혹은 리팩토링 간 기존 로직 혹은 베이스 플로우 등을 망치지 않을 것이라는 확신을 줌.
  • 빠른 피드백
    테스트할 부분을 타겟팅하여 테스팅하기 때문에 고쳐야 할 코드를 바로 알 수 있음.
  • 다큐멘테이션
    좋은 테스트 코드는 테스트 코드만으로도 맥락을 이해할 수 있고, 예제로도 이용 가능.
    이 플로우 혹은 함수가 어떤 동작을 하는지를 테스트 코드만 보고 알 수 있다.
    심지어 전체적인 흐름은 사용자 행동 기반으로 보여주는 테스트 코드가 더 보기 쉬울 수도.

테스트 단점

  • 개발 공수 많이 듦.
    • 개발 간 생산성 저하로 이어질 수도
    • 테스트 코드 또한 거대한 관리 포인트가 됨.
      개인적으로는 환경 구축 및 설정이 어려운 포인트였음
      (yaml 파일 및 스크립트 작성, 테스트 시점 등등)
  • 러닝 커브 필요.
    • 처음 셋업도 어려울 수 있고,
    • 처음 테스트 코드 작성은 결코 쉽지 않다.
  • 결국 개발자가 생각하는 엣지 케이스에 지나지 않음.
    • 결국 QA 엔지니어가 있지 않는 이상은 개발자가 생각해낸 케이스로 커버.

Cypress

cypress에서 e2e는
url에 랜딩해서 그 페이지에서 일어나는 컴포넌트, 일, 이벤트들을 테스팅할 수 있음.

강력한 테스팅 도구

  • e2e test
  • component test
  • integration test
  • unit test

모두 가능.

*component 테스트 같은 경우는 페이지에 상관없이 테스트하려는 컴포넌트에 초점을 맞추어 테스트하는 것.

작성법

주의 및 고려 사항

⚠️ E2E Test 작성 시

e2e 테스트를 짜려면 먼저 high quality의 test scenario가 있어야 한다.

그렇지 않으면

  • 신뢰성이 떨어지고, 관리가 어려워져 유지보수가 힘들어지고, 결국 깨지고 삭제해버릴 수도 있기 때문이다.

🤷 언제 동작하게 할 것인지?

e2e 테스트는 느리기 때문에 commit마다 하거나 on save 마다하는 등 자주 하게 되면 생산성이 떨어진다.

PR 단계에서 돌아가게 할 것인지, build 과정에서 돌아가게 할 것인지는 상황에 맞게 설정해야 할 것이다.

👮 도입한 순간 항상 명심

이 테스트 코드 또한 사실 거대한 관리 포인트가 하나 생긴 것이라고 볼 수 있다.

하지만 e2e는 바로 피드백을 받을 수 없는 테스트이기 때문에 만약 hotfix 이슈가 생기거나 플로우에 변화, 작은 변화라도 생기면 e2e 테스트까지 별도로 관리를 해주어야지 아니면 데드 코드에 불과해진다. (항상 개발 워크 플로우 포함 시켜야 함)

📍어디 어디 적용할 것 인지

e2e 테스트는 느리고 시간이 오래 걸리기에 모든 도메인에 다 추가하는 것이 좋은 것은 아닐 수 있다.

→ 클릭 마다 랜딩이 주기적으로 바뀌는 페이지이면 e2e를 도입하면 개발 공수가 많이 들고 자주 수정해주어야 한다.

실제 작성

setup 자체를 다루지는 않을 예정

home 페이지 랜딩 테스트

작성 코드

describe("home-landing-test", () => {
  // describe를 login 된 상태와 아닌 상태로 나눔.
  describe("landed home page with logged in", () => {
    // before: 작성된 테스트들이 모두 실행되기 전에 한 번 실행
    // beforeEach: 작성된 테스트들이 각각 실행되기 전마다 한 번씩 실행
    beforeEach(() => {
      // NOTE: set jwt token in cookie
      cy.setCookie("jwt", "test-token");

      // NOTE: fake response intercept
      cy.intercept("GET", `/auth/validate`, {
        statusCode: 200,
        body: {
          email: "e2e.test@test.kr",
          uuid: "test-uuid",
        },
      });

      // 홈 화면에 뿌려지는 데이터들 필요한 것이 있으면 intercept 해서 fake response 설정해주기.
      cy.intercept("GET", "api/user/profile", {
        statusCode: 200,
        body: {
          createdAt: "2021-11-29 19:27:06",
          description: null,
          email: "e2e.test@test.kr",
          name: "test te",
          gender: "male",
          userID: "test-uuid",
        },
      });

      // NOTE: go to home page
      cy.visit(`${process.env.BASE_URL}/`);
    });

    // h1 태그에 "안녕하세요"라는 text가 있어야 한다.
    it("should display greeting in korean", () => {
      cy.get("h1").contains("안녕하세요");
    });

    it("should display Sub Title", () => {
      cy.get("h2").contains("Sub Title");
    });
  });

  // 로그인 안되어 있는 경우
  describe("landed home page without being logged in", () => {
    it("should redirect to login page", () => {
      cy.visit(`${process.env.BASE_URL}/`);

      cy.url().should("include", "/signin");
    });
  });
});
  1. 로그인 상태 테스트

    1. 모든 테스트 시작 전 세팅
      • set token token은 실제로 받아오기 어려우므로 테스트로 cookie를 set 할 수 있다.(cy.setCookie)
      • response 실제 데이터 요청을 하기 때문에 실제 token이 없는 이 테스트에서는 validate api, user info api 등의 데이터도 백엔드에서 실제 값을 가져올 수 없다. 실제 테스트 화면에 나타난 데이터와 원하는 결과 데이터가 다를 수 있어 에러 발생 가능성 그 때 intercept 혹은 route를 사용하여 요청을 가로채 fake response를 설정하고 반환해줄 수 있다.
    2. h1 데이터 테스트

      h1 태그에 어떤 값이 들어가는지 확인 (cy.get("h1"))

      이후 chaning으로 사용할 수 있는 matcher는 매우 많아 docs 참고해가며 작성.

      • .element / #element 이렇게 jQuery 처럼 요소를 꺼내올 수 있음.

      대신 cy.get(”.element”) 이건 안됨. (cy.get은 동기적으로 요소를 반환해주지 않음.)

      $(”.element”) 이렇게 써야 한다.

  2. 검사

    • cypress open: cypress app을 이용해 연다
    • cypress run: cypress app 없이 console로 확인 가능.
  3. 기타

    • 사실 기능은 매우매우 다양하고 많다.
      • cross browsing (cypress app에서 chrome, firefox .. 지원)
      • snapshot
      • user interaction
      • 비동기
      • 등등
    • 그러나 모두 다루기에는 양이 많고 문서를 참조하는 게 더 좋을 것 같아서 전체적인 부분만 정리해두었다.

컨벤션

⇒ 코드 작성되면 거기에 따라서 컨벤션 작성

But,

Cypress Docs

  1. Set up the application state.
  2. Take an action.
  3. Make an assertion about the resulting application state.
  • Set up the application state.
    앱의 현재 특정 상태를 지정
    cy.visit("http://localhost:3000");
    
  • Take an action.
    유저가 행하게 될 동작을 테스트로 일으킴
    cy.get("button").click();
    
  • Make an assertion about the resulting application state.
    결과가 어떻게 되어야 하는지 설정
    cy.url().should("include", "/signin");
    

⇒ 이런 패턴은 정형화된 것이 아니기에 컨벤션은 상황에 따라서 정하면 좋을 것 같다.
예를 들어,

  • given과 userevent는 따로

    const $buttonToHome = $(".loginButton");
    
    $buttonToHome.click();
    
  • intercept 등은 어떻게 정리할 것인지
  • describe는 어떻게 나눌 건지
    • 시나리오에서 스텝을 나눠서 스텝은 describe로 할 건지
    • 성격을 하나로 묶어서 step은 it으로 할 건지 등등

개인적인 결론

테스트 코드가 현재 서비스의 코드를 커버하고 있는 정도를 나타내주는 coverage 수치를 무조건 100%로 맞추거나 몇 이상 지향하는 것보다는

현재 주어져 있는 상황에 맞게 최대한 커버하는 것 만으로도 좋지 않을까 한다.

주객전도가 되면 안되고,

분명히 테스트 코드를 작성하는 이유는

사용자가 프로덕트를 사용할 때 혹은 개발자가 프로덕트를 빌드할 때 신뢰성을 높이기 위함이다.

물론 커버리지가 높아지면 신뢰성이 더 좋다는 얘기지만,

개발 생산성도 고려해야 하고, 오히려 자주 변경되는 구간은 flexiblity를 놔두어도 되는 상황이 있지 않을까 생각해본다.

상황에 맞게 개발자들이 잘 논의해서 도입하면 좋을 것 같다.

우리 회사는 QA 엔지니어가 없기에 지점 등록 같은 메인 플로우 피쳐에도 적용하면 좋을 것 같긴 하다.

개발 공수와 관리 포인트는 무조건 많아지긴 할 것 같다.

기능에 초점을 맞춘다면 확실히 e2e만 도입하고, unit이나 ui 테스트는 보류하는 것도..

참고 자료

cypress start

frontend test

frontend test2


댓글남기기