Basic Test-Jest

유웅조·2020년 5월 8일
0

Basic

목록 보기
13/13

자동화된 테스트

테스트에는 여러 계층이 있을 수 있다. 그리고 완성도 있는 프로그램을 위해 각 계층마다, 심지어는 함수 하나마다 제대로 작동하는지를 확인하기 위해 QA를 진행히기 마련이다.

자동화된 테스트란 개발자, QA가 수동으로 진행하던 테스트에서, 무엇을 수행할 것인가에 대한 부분을 스크립트로 작성해서 코드로서 프로그램의 유효성을 검사하는 방법이다.

자동으로 테스트를 진행하게 되면 케이스를 잘 작성두기만 한다면 수동 테스트보다 더 많은 버그를 정확하게 찾아낼 수 있다.

그리고 한번 완성해 놓으면 지속적인 재사용이 가능해 매우 효율적이고 신속한 테스트가 가능하다.

반면, 단점으로는 색깔, 글꼴 등 미세한 UI의 시각적 요소는 테스트하기 어렵다.

또한 테스트의 범위를 설정하고 어디까지를 커버할 수 있는지가 모호하다는 점에서 완벽하지는 않다.

마지막으로 테스트를 위한 스크립트에 대한 충분한 검수와 디버깅에 추가적인 비용이 들어가며 만약 나중에 기능이 바뀌게 되면 테스트 코드 역시 많은 부분을 수정해야 할 수도 있다.

  • TDD(Test-Driven-Development)란

    TDD는 말그대로 테스트가 개발을 이끌어가는 개발 방법론이다. 즉, 어떠한 것을 코드로 만들 때 해당 코드에 대한 테스트를 먼저 완성한 뒤 그것을 기반으로 실제 코드를 작성해 나가는 것을 말한다.

    <익스트림 프로그래밍>의 창시자인 "켄트 벡"은 TDD에서 대표적인 인물인데 TDD의 핵심을 "결정(어떻게 구현할 것인가에 대한)과 피드백(성공과 실패) 사이의 갭에 대한 인식"이라며 추상적인 개념으로의 TDD에 무게를 둔다.

    TDD를 하게 되면 장점으로는 우선 개념적으로는 개발 시간이 단축된다고 한다.

    기능 구현이 끝났을 때를 "개발을 다했다"라고 했을 때, TDD를 하게 되면 개발 시간이 약 10% ~ 30% 단축된다고 한다.

    이렇게 말하는 가장 근본적인 이유는 개발 속도를 지연시키는 가장 큰 원인이 디버깅이기 때문이다.

    TDD를 하게 되면 디버깅에 소요되는 시간이 상대적으로 단축된다고 한다.

    그리고 디버깅 과정에서 정확한 이유를 알 수 있기 때문에 코드의 복잡성도 상대적으로 낮아진다고 한다.

    이에 반해 TDD의 단점은 오히려 아이러니하다.

    먼저 개발 시간이 증가하는 것이 TDD의 단점이다. 위에서의 장점과는 중복되면서 오히려 상반되는 내용인데, 이에 대한 이유는 실제 세계에서 개발의 완성은 주로 클라이언트에게 보여지는 순간을 의미하기 때문이다.

    기능이 완벽하지 않아도 단기적인 성과를 위해 우선 완성하는 경우가 많다.

    다음으로 그러한 이유 때문에 여태까지 개발해왔던 방식과 TDD는 매우 달라서 적응하는데 시간이 오래 걸릴 수 밖에 없다.

    마지막으로 경우에 따라 완벽한 테스트를 만드는 것이 굉장히 어려울 수가 있다. 그렇게 되면 우선 완성하는데에도 시간이 오래 걸릴 뿐더러 후에 기능이 크게 바뀌게 되면 이에 따른 테스트를 수정하는데에도 큰 공수가 따른다.

단계별 테스트

  1. UNIT TEST

코드 상에서 모듈로 분리할 수 있는 가장 작은 단위를 말한다. 가장 쉽게 클래스나 함수 하나까지 유닛 테스트라고 볼 수 있다.

작은 단위의 모듈이 제대로 작동하는지 세밀한 부분까지의 테스트가 가능하고 넓은 범위의 테스트보다 빠르게 진행할 수 있다.

다만, 의존성이 있는 모듈의 경우 각 모듈의 상호 작용에 대한 부분은 테스트하지 못하기 때문에 만약 모듈 간의 관계에 어떠한 변화가 생기게 되면 영향을 많이 받을 수도 있다.

  1. INTEGRATION TEST

유닛 테스트에서의 모듈을 모두 한데 통합하여 테스트하는 것을 통합 테스트라고 한다.

개별적인 모듈은 정상적으로 작동하더라도 모듈들이 통합되었을 때 유기적으로 잘 작동하는지에 대한 테스트이다.

유닛 테스트보다 넓은 범위에서의 테스트이기 때문에 개별 모듈의 변경에 대해 서로의 인터페이스만 잘 구축해놓았다면 크게 깨지지 않는다는 장점이 있다.

하지만 테스트 경웨 따라 모듈에 대한 테스트 중복이 일어날 가능성도 많다.

  1. End To End TEST

E2E 테스트는 기능 테스트 혹은 UI 테스트로 불리기도 한다. 말그대로 Front End to Back End가 모두 통합된 하나의 제품을 테스트하는 것을 말한다.

실제 사용자의 환경과 가장 유사한 환경에서 진행하기 때문에 실제 상황에서 발생할 수 있는 에러를 발견할 수 있다.

내부 모듈이나 그 사이의 관계에 거의 영향이 없기 때문에 큰 범위의 리펙토링에도 깨지지 않는다.

하지만 앞선 테스트보다 소요 시간이 오래 걸리고, 세부 모듈들이 갖는 다양한 상황에 대한 변수가 많아 코드를 작성하기가 어렵고, 필연적으로 여러 모듈에 대해 중복 테스트를 하게 되기 쉽다.

Stub, Mock

  • Mocking

    mocking이란 유닛 테스트를 작성할 때, 해당 코드가 의존하는 부분을 가짜(mock)로 대체하는 기법을 말한다. 일반적으로 유닛 테스트의 해당 코드가 의존하는 부분을 직접 생성하는 것이 까다로울 때 mocking을 많이 사용한다.

    예를 들어서 데이터베이스에서 데이터를 삭제하는 코드에 대한 단위 테스트를 작성할 때, 실제 데이터베이스를 사용한다면 여러가지 문제점이 발생할 수 있다.

    위의 경우처럼 I/O, Network 작업이 포함된 테스트는 실행 속도가 떨어질 수 있고, 테스트가 인프라의 의존을 너무 많이 하게 되어 영향을 많이 받는다.

    또한 이러한 테스트들의 양이 많아지고 케이스가 많아지게 되면 큰 이슈가 될 수 있다.

    만약 테스트 자체를 위해 데이터베이스와 연결하고 트랜잭션을 생성하고 쿼리를 전송하는 코드가 실제 테스트보다 더 길어질 수도 있다.

    무엇보다도 이렇게 작성된 테스트는 실질적으로 더이상 유닛 테스트가 아니게 된다.

    mocking은 이런 상황에서 실제 객체인 척하는 가짜 객체를 생성하는 매커니즘을 제공한다. 또한 테스트가 진행되면서 가짜 객체의 상태 등을 기억하기 때문에 내부적으로 어떻게 작동했는지도 검증할 수 있다.

    spy

    mocking에는 spy라는 개념이 있다. 테스트가 작동하는 과정에서 어떤 객체에 속한 함수의 구현을 가짜로 대체하지 않고, 해당 함수의 호출 여부와 어떻게 호출되었는지만을 앙아내야 할 때 사용하면 된다.

  • Stub

    stub은 아직 준비되지 못한 코드를 미리 정해진 답변으로 반환할 수 있도록 하는 매커니즘이다.

    가짜 객체가 실제로 동작하는 것처럼 보이게 만들어 놓은 객체로 호출자를 실제 구현물로부터 격리시켜 독립적인 테스트를 진행할 수 있도록 한다.

    주로 아직 구현이 되지 않은 함수나, 라이브러리에서 제공하는 함수를 사용하고자 할 때, 혹은 복잡한 논리 흐름을 가져 테스트를 단순화하고 싶을 때, 의존성을 가지는 유닛의 응답을 모사혀여 독립적인 테스트를 수행하고자 할 때 사용된다.

    stub을 사용하게 되면 아직 구현이 되지 않았더라도, interface만으로도 테스트하고 개발할 수 있고 테스트의 단순화를 통해 다양한 응답 결과에 대한 촘촘한 케이스 검사를 수행할 수 있다.

Jest

Jest는 단순함에 초점을 둔, 페이스북에서 만든 오픈 소스 자바스크립트 테스트 프레임워크이다. 비교적 사용이 간단하며 Babel, Typescript, Node.js, React, Vue 등에 모두 사용할 수 있다.

테스트가 유니크한 전역 상태를 갖도록 해 모든 테스트를 평행적으로 수행이 가능하게 한다. 또한 빠른 테스트를 위해 이전 테스트에서 실패했던 것을 가장 먼저 실행하고 테스트의 수행 시간을 예측해 실행 순서를 재배치한다.

--coverage 플래그를 통해 매우 간단하게 테스트의 코드 커버리지를 파악할 수 있다.

또한 assertion과 같은 Jasmine 스타일의 API를 사용하기 때문에 기존 사용자들도 쉽게 사용할 수 있으며 다양한 mock API를 제공해 쉽게 더미 객체를 생성, 활용할 수 있다.

  • Jest 이외의 테스트 프레임워크

    우선 Mocha, 확장성이 용이한 것이 대표적인 장점이라고 한다. 모카 역시 Jest와 마찬가지로 Node.js 환경에서 구동되어 브라우저 환경보다 훨씬 빠르고 가볍다.

    확장성이 좋다는 것은 다르게 말해서 여러가지 라이브러리를 사용해서 기능을 확장할 수 있다는 의미이다. 모카의 경우 Assertion은 주로 Chai를 사용하고, 테스트 더블은 주로 Sinon을 사용한다.

    두번째로 Karma + Jasmine의 조합은 주로 브라우징 테스트가 필요할 때 사용한다. Jasmine은 Node.js와 브라우저 환경 모두에서 사용이 가능하기 때문이다. 모카의 경우, 여러가지 라이브러리를 사용해야 했지만 Jasmine은 모든 기능을 통합해서 제공하기 때문에 추가적인 라이브러리가 필요 없다.

    일단 Jasmine으로 작성한 코드를 브라우저 환경에서 실행하기 위해서는 Karma를 사용하면 된다. 로컬 웹서버를 구동한 뒤, 테스트 소스 코드를 모두 로드하는 HTML 페이지를 생성하고, 브라우저에서 실제 고둥되며 실행된 결과를 받아서 지정된 리포터를 사용해 다양한 방식으로 출력해준다.

  • Puppeteer

    Puppeteer는 Node.js 라이브러리로 headless Chrome 혹은 Chronium을 DevTools Protocol위에서 제어하기 위한 고수준 API를 제공한다.

    Headless Chrome이란 GUI가 아닌 CLI에서 작동하는 브라우저를 말하는데, 백그라운드에서 작동한다는 것 외에 일반적인 브라우저와 같은 방식의 렌더링을 사용한다. 다만, 만든 화면을 사용자에게 보여주지는 않는다.

    브라우저 상에서 할 수 있는 것들은 대부분 Puppeteer로 할 수 있다. 예를 들어, 스크린샷을 찍어 PDF로 만들거나, SPA로 되어 있는 페이지를 크롤링하거나 UI 테스트, 키보드 입력 자동화, 최신 버전의 크롬 브라우저 환경에서의 테스트 등 매우 다양하다.

0개의 댓글