[코드스쿼드] 프론트엔드 Lv3 - STEP10 테스트코드 작성하기
코드스쿼드 프론트엔드 Lv3 과정 중 [STEP 10] 테스트코드 작성하기를 구현하면서 발생한 이슈들에 대해서 기록한 글 입니다
목표
테스트 코드를 작성한다
- jest 를 사용
- 유틸리티 함수 및 DOM 과 Event 를 테스트
- MVC 로 구현했다면, M,V,C 를 모두 각각 테스트
- 그외 클래스 형태라면 클래스별 골고루 테스트케이스를 작성
개발로그
JEST 사용
코드스쿼드 강의에서 Mocha 와 Chai 로 Unit Test 를 하는 것을 배웠다. 일단은 Mocha 와 Chai 가 무엇을 하는건지 부터 나눠볼까 :)
MochaJavaScript 프레임워크로서 node, 브라우저, 비동기 테스트까지 할 수 있다. Mocha 테스트는 연속적으로 실행되므로, 유연하고 정확한 보고가 가능하다.
ChaiNode.js와 브라우저를 위한 BDD/TDD Assertion 라이브러리로, 자바스크립트 테스트 프레임워크와 함께 사용할 수 있다.
JestJest는 Facebook에서 React 애플리케이션을 포함한 모든 JavaScript 코드를 테스트하는 데 사용되며, Jest의 철학 중 하나는 통합 된 “zero-configuration”경험을 제공하는 것이다. 우리는 엔지니어가 즉시 사용 가능한 도구를 제공받을 때 더 많은 테스트를 작성하게되고 결과적으로 더 안정적이고 건강한 코드 기반을 얻게된다는 것을 알게되었다.
npm install --save-dev jest일단 Jest 를 사용하려면 install 을 해주어야 한다.
package.json“scripts” 부분에 “test” 를 “jest” 로 설정한다.
일단은 Utility 부터 테스트 해보자
Utility 를 import 해야하는데 import 하는 과정에서 에러가 난다.

JavaScript 에서는 CoffeeScript 처럼 비슷한 부류의 언어를 JavaScript 로 바꿔주는 것을
트랜스파일이라고 한다.ES2015 의 트랜스파일러는 대표적으로 Traceur 과 Babel 이 존재한다. Bable 을 사용하고 싶다면 Babel Preset 을 참고하여, 설정을 해주어야 하는데
npm install과.babelrc파일을 생성하는 것이다. 그러면 ES6(ES2015) 에서 사용하는 import 를 정상적으로 사용할 수 있을 것이다.그리고 import 할 때, export 를 Utility 로 명시하고, import 는 util 로 하려니 당연히 안받아진다는 것을 기억하자. as 를 사용하는 것 아니면 export 한 네이밍을 그대로 가져올 것을 명심하자.
왠지 node_modules 폴더가 걸린단 말이지
npm install을 통해서 모듈들을 설치하니 몇천개의 파일이 git 으로 수루룩 흘러들어갈 것만 같았다. 난 그것을 모른채git push를 진행했고, 이후 크롱한테 물어봤더니 gitignore 를 통해서.. 제외시켜야 했다.그래서 git을 한단계 무르고
git reset HEAD^강제로 commit 을 날려주어서 node_modules 이 push 된 커밋을 무효화시킬 수 있다.test
querySelector 함수를 어떻게 테스트해야할지 잘 감이 안온다. HTML 연계가 되어있지 않아서, querySelector 을 날려도 undefined 만 출력된다.
snodeList를 만드는 방법이 있다. 노드는
document.createElement를 사용해서 만들면 된다 (ex. div)var list = singleNode(노드); // for example list instanceof NodeList; // true그리고 expected 에 배열을 새로 생성해서 push 해주었는데, 분명 똑같은 값이 나오는데 toBe 대신 toEqual 을 사용하라고 경고문이 출력된다.

나중에 Jest 개발문서를 참고해서 toBe 와 toEqual 의 차이점도 기술해야겠다.
toEqual두 객체의 값이 같은지 확인하려는 경우에 사용한다. 객체 동일성을 검사하는 것이 아닌 모든 필드의 동등성을 재귀적으로 검사한다. 기본적으로
toBe와toEqual은 다르게 동작한다.함수 테스트
함수테스트가 굉장히 어렵다. mock 이라는 객체(?)를 이용해야 하는데, 이것을 이해하기가 좀 힘들다. dummy data 를 만들어주는 것(?) 이라고만 인식하고 있는데, 조금 더 찾아보고 코드를 많이 봐야할 것 같다.
.toHaveBeenCalled().not.toHaveBeenCalled()모의 함수가 호출되었는지 확인하는데 사용한다.
.toHaveBeenCalledTimes(number)모의 함수가 정확한 횟수만큼 호출되었는지 확인하는데 사용한다.
.toHaveBeenCalledWith(arg1, arg2, ...)모의 함수가 특정 인수로 호출되었는지 확인하는데 사용한다.
.dispatchEvent(event)event 는 Event Object 로써 디스패치될 이벤트입니다.
.event.preventDefault()이벤트를 취소할 수 있는 경우, 이벤트 전파를 막지 않고 해당 이벤트를 취소합니다.
테스트할 때 막히는 것을 차근차근 정리해보자.
- Log.test.js
- 일단 로그 관련된 부분은
logView와logPresenter가 존재한다.logPresenter는model과 연관되어 있으므로 전부 import 를 일단 진행하기로 했다. - 그리고 전역에 new 키워드를 사용해서 mainView, model, presenter, logView 를 선언하였다. (괜찮은 방법인지는 모르겠다, 왠지 안좋은 것 같긴한데 테스트라서 상관없나?)
- beforeEach 함수는
it으로 시작하는 함수가 시작될 때마다 실행하는 함수이다. - 특정 함수에
jest.fn()을 설정하면, 모의함수가 생성된다. .mockReturnValue(value)는jest.fn()함수에서 적용 가능한 명령어이다.- 해당 함수의 반환값을
toHaveReturnedWith(true, false)로 테스트 할 수 있다. - 이전에, 한번 해당
jest.fn()함수를 호출해야한다.
- 일단 로그 관련된 부분은
Control.test.js
클릭이벤트 등록 이벤트를 어떻게 테스트해야하는지 감이 잘 안온다.
expect(controlView.registerClickEventToProductClickNumBtn).toHaveReturned()
expect(controlView.registerClickEventToProductClickNumBtn.mock.calls.length).toBe(1)
- 함수가 호출되는 카운트가 하나씩 체크됨
controlPresenter 의 생성자에서 버튼이벤트를 등록하는데,
TypeError: Cannot read property 'addEventListener' of null이라는 에러를 만날 수 있었다.- 해당 에러를 해결하는 방법은 생성자(constructor) 을 mock 형태로 만드는 것인데
jest.mock(‘해당 js 파일위치’); 로 상단부분에 선언해주면 된다.
jest.mock('../Presenter/VendingMachineControlPresenter.js');
해당 ControlPresenter 에 mock 함수를 적용하니, 모든 함수들이 mock 함수로 바뀌었다.
호출 후
toHaveBeenCalledTimes(1)로 테스트를 진행하면, 정상적으로 통과한다.그런데, 이 호출횟수가 의미가 있는것인가?
생성자에서 새로운 코드를 삽입하였다
const itemPanelDiv = this.util.getNodeData('#item-selector-panel'); // if(!itemPanelDiv) throw new Error('NO EXIST NODE'); if(!itemPanelDiv) return true;- 클릭이벤트를 등록하는 부분인데, 해당
itemPanelDiv가 존재하지 않을 경우, 리턴시켜주는 코드로 동작하게 하였다. - jest 에서 테스트할 때, 정상적으로 진행되었다. 그래서 mock 함수로 대체된 함수들이 정상적으로 돌아왔고
- model의 데이터를 통해 데이터를 지정하는 부분들이 정상적으로 진행되었다.
디버깅
학습
질문
