인프런에서 견고한 JS 소프트웨어 만들기를 수강하며 적은 강의노트입니다.
보다 자세한 내용은 강의를 통해 확인하실 수 있습니다.
클릭카운터 모듈 - 스펙1
전역공간에 있는 counter변수를 ClickCounter안에서 관리
ClickCounter모듈의 getValue()는 카운터 값을 반환한다.
테스트 코드 작성 (적색단계)
xxxxxxxxxx describe('getValue()', ()=> { it('초기값이 0인 카운터 값을 반환한다', ()=> { const counter = App.ClickCounter() expect(counter.getValue()).toBe(0) }) })
모듈 생성 (녹색단계)
xxxxxxxxxxvar App = App || {}App.ClickCounter = () => { return { getValue() { return 0 } }}
상수 변경 (리팩터단계)
xxxxxxxxxxvar App = App || {}App.ClickCounter = () => { let value = 0 return { getValue() { return value } }}
클릭카운터 모듈 - 스펙2
테스트 코드 작성 (적색단계)
xxxxxxxxxx describe('increase()', ()=> { it('카운터를 1 올린다', ()=> { // 준비 const counter = App.ClickCounter() // 실행 counter.increase() // 단언 expect(counter.getValue()).toBe(1) }) })
모듈 생성 (녹색단계)
xxxxxxxxxxvar App = App || {}App.ClickCounter = () => { let value = 0 return { getValue() { return value }, increase() { value++ } }}중복코드를 제거하기 위한 재스민 함수
xxxxxxxxxxdescribe(() => { beforeEach(()=> { // 1 }) afterEach(() => { // 3 }) it(() => { // 2 })})변경결과
xxxxxxxxxxdescribe('App.ClickCounter', ()=> { let counter beforeEach(() => { counter = App.ClickCounter() }) describe('getValue()', ()=> { it('초기값이 0인 카운터 값을 반환한다', ()=> { expect(counter.getValue()).toBe(0) }) }) describe('increase()', ()=> { it('카운터를 1 올린다', ()=> { // 실행 counter.increase() // 단언 expect(counter.getValue()).toBe(1) }) })})초기값이 0이 아닌경우를 수정
xxxxxxxxxx describe('increase()', ()=> { it('카운터를 1 올린다', ()=> { const initValue = counter.getValue() // 실행 counter.increase() // 단언 expect(counter.getValue()).toBe(initValue + 1) }) })
클릭카운터뷰 모듈 - 스펙1
카운터 데이터는 DOM에 반영되어야 함
데이터를 출력하고 이벤트 핸들러를 바안딩하는 일을 담당
ClickCounterView모듈의 updateView()는 카운트 값을 출력
테스트 코드 작성 (적색단계)
xxxxxxxxxxdescribe('App.ClickCountView', ()=> { let clickCounter, updateEl, view beforeEach(() => { clickCounter = App.ClickCounter() updateEl = document.createElement('span') view = App.ClickCountView(clickCounter, updateEl) }) describe('updateView()', ()=> { it('ClickCounter의 getValue() 값을 출력한다', ()=> { const counterValue = clickCounter.getValue() view.updateView() // 단언 expect(updateEl.innerHTML).toBe(counterValue.toString()) }) })})
모듈 생성 (녹색단계)
xxxxxxxxxxvar App = App || {}App.ClickCountView = (clickCounter, updateEl) => { return { updateView() { updateEl.innerHTML = clickCounter.getValue() } }}
ClickCountView에 의존성 주입이 되었나...?
테스트 코드
xxxxxxxxxx it('clickCounter를 주입하지 않으면 에러를 던진다.', () => { const clickCounter = null const updateEl = document.createElement('span') const actual = () => App.ClickCountView(clickCounter, updateEl) expect(actual).toThrowError() }) it('updateEl를 주입하지 않으면 에러를 던진다.', () => { const clickCounter = App.ClickCounter() const updateEl = null const actual = () => App.ClickCountView(clickCounter, updateEl) expect(actual).toThrowError() })모듈 수정
xxxxxxxxxxvar App = App || {}App.ClickCountView = (clickCounter, updateEl) => { if(!clickCounter) throw Error('clickCounter') if(!updateEl) throw Error('clickCounter') return { updateView() { updateEl.innerHTML = clickCounter.getValue() } }}
클릭카운터뷰 모듈 - 스펙2
ClickCountView모듈의 increaseAndUpdateView()는 카운트 값을 증가하고 그 값을 출력한다.
ClickCounter의increase함수를 실행한다.updateView함수를 실핸한다.
테스트 더블(스파이스, spies)
단위 테스트 패턴으로, 테스트하기 곤란한 컴포넌트를 대체하여 테스트하는 것으로 특정한 동작을 흉내만 낼뿐이지만 테스트 하기에는 적합하다.
- Dummy: 인자를 체우기 위해 사용.
- Sturb: 더미를 개선하여 실제 동작하게끔 만든 것. (리턴값을 하드코딩)
- Spy: 스텁과 유사. 내부적으로 기록을 남기는 추가기능.
- Fake: 스텁에서 발전한 실제 코드, 운영에서는 사용할 수 없음. (실제 값을 리턴)
- Mock: Dummy, Sturb, Spy를 혼합한 형태.
재스민에서 사용법
xxxxxxxxxx// MyApp 모듈의 foo 함수를 감시하도록 설정한다.spyOn(MyApp, 'foo')// 특정 행동을 한 뒤bar()// 감시한 함수가 실행되었는지 체크한다.expect(MyApp.foo).toHaveBeenCalled()// 즉, bar() 함수가 MyApp.foo() 함수를 실행하는지 검증하는 코드이다.
테스트 코드 작성 (적색단계)
xxxxxxxxxx describe('increaseAndUpdateView()는', ()=> { it('ClickCounter의 increase 를 실행한다', ()=> { spyOn(clickCounter, 'increase') view.increaseAndUpdateView() expect(clickCounter.increase).toHaveBeenCalled() }) it('updateView를 실행한다', ()=> { spyOn(view, 'updateView') view.increaseAndUpdateView() expect(view.updateView).toHaveBeenCalled() }) })
모듈생성 (녹색단계)
xxxxxxxxxxvar App = App || {}App.ClickCountView = (clickCounter, updateEl) => { if (!clickCounter) throw new Error(App.ClickCountView.messages.noClickCounter) if (!updateEl) throw new Error(App.ClickCountView.messages.noUpdateEl) return { updateView() { updateEl.innerHTML = clickCounter.getValue() }, increaseAndUpdateView() { clickCounter.increase() this.updateView() } }}App.ClickCountView.messages = { noClickCounter: 'clickCount를 주입해야 합니다', noUpdateEl: 'updateEl를 주입해야 합니다'}
클릭카운터뷰 모듈 - 스펙3
클릭 이벤트가 발생하면 increaseAndUpdateView()를 실행한다.
테스트 코드 작성(적색단계)
increaseAndUpdateView를 바인딩할 돔 엘리먼트(triggerEl)을 주입받자
xxxxxxxxxx it('클릭 이벤트가 발생하면 increseAndUpdateView를 실행한다', ()=> { // 준비 spyOn(view, 'increaseAndUpdateView') // click! triggerEl.click() // 단언 expect(view.increaseAndUpdateView).toHaveBeenCalled() })모듈생성 (녹색단계)
xxxxxxxxxxvar App = App || {}App.ClickCountView = (clickCounter, options) => { if (!clickCounter) throw new Error(App.ClickCountView.messages.noClickCounter) if (!options.updateEl) throw new Error(App.ClickCountView.messages.noUpdateEl) if (!options.triggerEl) throw new Error(App.ClickCountView.messages.noTriggerEl) const view = { updateView() { options.updateEl.innerHTML = clickCounter.getValue() }, increaseAndUpdateView() { clickCounter.increase() this.updateView() } } options.triggerEl.addEventListener('click', () => { view.increaseAndUpdateView() }) return view}App.ClickCountView.messages = { noClickCounter: 'clickCount를 주입해야 합니다', noUpdateEl: 'updateEl를 주입해야 합니다', noTriggerEl: 'triggerEl를 주입해야 합니다.',}
'FrontEnd' 카테고리의 다른 글
| 견고한 JS 소프트웨어 만들기 강의노트5 (0) | 2019.09.29 |
|---|---|
| 견고한 JS 소프트웨어 만들기 강의노트4 (0) | 2019.09.29 |
| 견고한 JS 소프트웨어 만들기 강의노트3 (0) | 2019.09.15 |
| 견고한 JS 소프트웨어 만들기 강의노트1 (0) | 2019.09.15 |
| 자바스크립트 Blob 이란? (1) | 2019.08.13 |