SlideShare a Scribd company logo
1 of 111
Download to read offline
React로
TDD 쵸큼 맛보기
김훈민@네이버
나는자바스크립트개발자다
김코딩
스마트에디터 3.0, 프론트엔드 개발 - @네이버
기술 블로그(huns.me)에 아주 가끔 글 쓰기
페이스북 커뮤니티 프론트엔드개발그룹 운영하는 척
네이버 사내 리액트 미트업 운영하는 척
Facebook은 React를 왜 만들었을까 - @FBDG 2015
Angular2 vs React, React vs Angular2 - @Deview 2016
오늘의 주제는 …
단위 테스트 어떻게 작성하나요?
TDD, 왜 해요?
TDD 하면 뭐가 좋아요?
TDD 하면 설계를 잘 할 수 있나요?
TDD 하면 클린 코드를 작성할 수 있나요?
TDD 하는 모습이 궁금해요
오늘의 주제는 …
단위 테스트 어떻게 작성하나요?
TDD, 왜 해요?
TDD 하면 뭐가 좋아요?
TDD 하면 설계를 잘 할 수 있나요?
TDD 하면 클린 코드를 작성할 수 있나요?
TDD 하는 모습이 궁금해요
오늘 만들 녀석은,
“막막” 간단한 Spinbox
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
환경은…?
Webpack
ES2015 with babel
Jest
Enzyme
들어가기 전에
테스트 설정은 잘 되어있나?
구현 코드 테스트 코드
it('스핀박스 생성할 수 있다.', () => {
// given - 어떤 조건 또는 상황일 때
// when - 어떤 행위를 하면
// then - 결과가 무엇이어야 한다
});
it('스핀박스를 생성할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
it('스핀박스 생성할 수 있다.', () => {
// setup
// exercise
// verify
});
“어디에서 시작하지?”
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
“어디에서 시작하지?”
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
it('스핀박스를 생성할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
it('스핀박스를 생성할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
복사해서 붙여넣기
it('스핀박스를 생성할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
const input = spinbox
.find('input')
.getDOMNode();
expect(input.value).toEqual(200);
});
import React from 'react';
const Spinbox = () => (
<div>
<input type=“text" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
const input = spinbox
.find('input')
.getDOMNode();
const actualValue = Number(input.value);
expect(actualValue).toEqual(200);
});
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
넘나 신경 쓰이는 것!
TDD는
테스트와 구현을 반복하면서
계단을 하나씩 쌓아가는 여정
“테스트 코드”는
어떻게 검증해야 하지?
두 번째 요구사항
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
const input = spinbox
.find('input')
.getDOMNode();
const actualValue = Number(input.value);
const defaultValue = 200;
expect(actualValue).toEqual(defaultValue);
});
it('입력 폼에 999를 입력할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
const input = spinbox
.find('input')
.getDOMNode();
const actualValue = Number(input.value);
const defaultValue = 200;
expect(actualValue).toEqual(defaultValue);
});
it('입력 폼에 999를 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '999'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200"
onChange={ () => {
this.setState({
value: 999
})
} } />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
아놬! 무상태 컴포넌트!
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
안전할 때 까지
되돌리기!
it('입력 폼에 숫자 값을 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '999'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
it.skip('입력 폼에 숫자 값을 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '999'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
import React from 'react';
const Spinbox = () => (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
import React from ‘react';
class Spinbox extends React.Component {
render() {
return (
<div>
<input type="text"
defaultValue="200" />
<button>▲</button>
<button>▼</button>
</div>
);
}
}
Spinbox.defaultProps = {};
Spinbox.propTypes = {};
export default Spinbox;
it.skip('입력 폼에 숫자 값을 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '999'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
it('입력 폼에 999를 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '999'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
class Spinbox extends React.Component {
componentWillMount() {
this.state = {
value: 200
};
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ () => {
this.setState({
value: 999
})
} } />
<button>▲</button>
<button>▼</button>
</div>
);
}
}
// 생략 …
class Spinbox extends React.Component {
componentWillMount() {
this.state = {
value: 200
};
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ () => {
this.setState({
value: 999
})
} } />
<button>▲</button>
<button>▼</button>
</div>
);
}
}
class Spinbox extends React.Component {
componentWillMount() {
this.state = {
value: 200
};
this.handleChangeInput = this.handleChangeInput.bind(this);
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button>▲</button>
<button>▼</button>
</div>
);
}
handleChangeInput() {
this.setState({
value: 999
});
}
}
it('스핀박스를 생성할 수 있다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// then
expect(spinbox).toBeDefined();
});
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … });
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … });
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '0'
}
});
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(0);
});
handleChangeInput() {
this.setState({
value: 999
});
}
handleChangeInput(e) {
this.setState({
value: e.target.value
});
}
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => {
// given
// when
const spinbox = mount(<Spinbox />);
// 생략…
});
it('입력 폼에 999를 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// 생략…
});
it('입력 폼에 0을 입력할 수 있다.', () => {
// given
const spinbox = mount(<Spinbox />);
// 생략…
});
let spinbox;
beforeEach(() => {
spinbox = mount(<Spinbox />);
});
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … });
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => { … });
it('입력 폼에 999을 입력할 수 있다.', () => {
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(999);
});
it('입력 폼에 0을 입력할 수 있다.', () => {
// then
const inputNode = input.getDOMNode();
const actualValue = Number(inputNode.value);
expect(actualValue).toEqual(0);
});
let spinbox;
beforeEach(() => {
spinbox = mount(<Spinbox />);
});
function getValueFromInputNode(input) {
const inputNode = input.getDOMNode();
return Number(inputNode.value);
}
it('입력 폼에 999를 입력할 수 있다.', () => {
// …생략
// then
const actualValue = getValueFromInputNode(input);
expect(actualValue).toEqual(999);
});
it('입력 폼에 0을 입력할 수 있다.', () => {
// …생략
// then
const actualValue = getValueFromInputNode(input);
expect(actualValue).toEqual(0);
});
세 번째 요구사항
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => {
// given
// when
const input = spinbox.find('input');
input.simulate('change', {
target: {
value: '0'
}
});
// then
const actualValue = getValueFromInputNode(input);
expect(actualValue).toEqual(0);
});
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => {
// given
const defaultValue = 200;
// when
const incrementBtn = spinbox.find('[data-name="increment"]');
incrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue + 1);
});
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment">▲</button>
<button>▼</button>
</div>
);
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment"
onClick={ () => {
this.setState({
value: 201
})
} }>▲</button>
<button>▼</button>
</div>
);
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment"
onClick={ () => {
this.setState({
value: 201
})
} }>▲</button>
<button>▼</button>
</div>
);
}
componentWillMount() {
this.state = {
value: 200
};
this.handleChangeInput = this.handleChangeInput.bind(this);
this.handleClickIncrement = this.handleClickIncrement.bind(this);
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment"
onClick={ this.handleClickIncrement }>▲</button>
<button>▼</button>
</div>
);
}
handleClickIncrement() {
this.setState({
value: 201
});
}
it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => {
// given
const defaultValue = 200;
// when
const incrementBtn = spinbox.find('[data-name="increment"]');
incrementBtn.simulate('click');
incrementBtn.simulate('click');
incrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue + 3);
});
handleClickIncrement() {
this.setState({
value: 201
});
}
handleClickIncrement() {
this.setState({
value: this.state.value + 1
});
}
it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … });
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => { … });
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … });
it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … });
describe('기본값 >', () => {
it('스핀박스를 생성하면 기본값이 200이어야 한다.', () => { … });
});
describe('값 입력 >', () => {
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => { … });
});
describe('값 증가 >', () => {
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … });
it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … });
});
describe(‘값 입력 >', () => {
it('입력 폼에 999를 입력할 수 있다.', () => {
// given
// when
const input = spinbox.find('input');
// … 생략
});
it('입력 폼에 0을 입력할 수 있다.', () => {
// given
// when
const input = spinbox.find('input');
// … 생략
});
});
describe(‘값 입력 >', () => {
let input;
beforeEach(() => {
input = spinbox.find('input');
});
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => { … });
});
describe(‘기본값 >', () => {
it('스핀박스를 생성하면 기본값이 200이어야 한다.', () => { … });
});
describe('값 입력 >', () => {
let input;
beforeEach(() => {
input = spinbox.find('input');
});
it('입력 폼에 999를 입력할 수 있다.', () => { … });
it('입력 폼에 0을 입력할 수 있다.', () => { … });
});
describe('값 증가 >', () => {
const defaultValue = 200;
let incrementBtn;
beforeEach(() => {
incrementBtn = spinbox.find('[data-name="increment"]');
});
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … });
it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … });
});
얻는 것과 잃는 것
변경의 포인트는 집중
코드는 덜 직관적
it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => {
// given
// when
incrementBtn.simulate('click');
incrementBtn.simulate('click');
incrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue + 3);
});
뭘까?
네 번째 요구사항
기본값은 200
값 입력
증가 버튼을 클릭하여 값이 1 증가
감소 버튼을 클릭하면 값이 1 감소
describe('값 증가 >', () => {
const defaultValue = 200;
let incrementBtn;
beforeEach(() => {
incrementBtn = spinbox.find('[data-name="increment"]');
});
it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => {
// given
// when
incrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue + 1);
});
});
describe('값 감소 >', () => {
const defaultValue = 200;
let decrementBtn;
beforeEach(() => {
decrementBtn = spinbox.find('[data-name="decrement"]');
});
it('감소 버튼을 클릭하여 값을 1 감소시킬 수 있다.', () => {
// given
// when
decrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue - 1);
});
});
class Spinbox extends React.Component {
componentWillMount() {
this.state = {
value: 200
};
this.handleChangeInput = this.handleChangeInput.bind(this);
this.handleClickIncrement = this.handleClickIncrement.bind(this);
this.handleClickDecrement = this.handleClickDecrement.bind(this);
}
render() { … }
handleClickDecrement() {
this.setState({
value: this.state.value - 1
});
}
handleClickIncrement() { … }
handleChangeInput(e) { … }
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment"
onClick={ this.handleClickIncrement }>▲</button>
<button>▼</button>
</div>
);
}
render() {
return (
<div>
<input type="text"
value={ this.state.value }
onChange={ this.handleChangeInput } />
<button data-name="increment"
onClick={ this.handleClickIncrement }>▲</button>
<button data-name="decrement"
onClick={ this.handleClickDecrement }>▼</button>
</div>
);
}
이걸로 충분할까?
불안하다면 망설이지 말고
테스트 작성!
it('감소 버튼을 세 번 클릭하여 값을 3 감소시킬 수 있다.', () => {
// given
// when
decrementBtn.simulate('click');
decrementBtn.simulate('click');
decrementBtn.simulate('click');
// then
const actualValue = getValueFromInputNode(spinbox.find('input'));
expect(actualValue).toEqual(defaultValue - 3);
});
끝!
감사합니다!

More Related Content

What's hot

프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oopYoung-Beom Rhee
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++KWANGIL KIM
 
C++ Concurrency in Action 9-2 Interrupting threads
C++ Concurrency in Action 9-2 Interrupting threadsC++ Concurrency in Action 9-2 Interrupting threads
C++ Concurrency in Action 9-2 Interrupting threadsSeok-joon Yun
 
2.Startup JavaScript - 연산자
2.Startup JavaScript - 연산자2.Startup JavaScript - 연산자
2.Startup JavaScript - 연산자Circulus
 
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Circulus
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitiveNAVER D2
 
Angular2 가기전 Type script소개
 Angular2 가기전 Type script소개 Angular2 가기전 Type script소개
Angular2 가기전 Type script소개Dong Jun Kwon
 
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH, 케이티하이텔
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료욱진 양
 
Python Programming: Function
Python Programming: FunctionPython Programming: Function
Python Programming: FunctionChan Shik Lim
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)beom kyun choi
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSCirculus
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features SummaryChris Ohk
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdfHyosang Hong
 
C++ 11 에 대해서 쉽게 알아봅시다 1부
C++ 11 에 대해서 쉽게 알아봅시다 1부C++ 11 에 대해서 쉽게 알아봅시다 1부
C++ 11 에 대해서 쉽게 알아봅시다 1부Gwangwhi Mah
 
Startup JavaScript 4 - 객체
Startup JavaScript 4 - 객체Startup JavaScript 4 - 객체
Startup JavaScript 4 - 객체Circulus
 
Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택JinTaek Seo
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰beom kyun choi
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리ETRIBE_STG
 

What's hot (20)

프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++포트폴리오에서 사용한 모던 C++
포트폴리오에서 사용한 모던 C++
 
C++ Concurrency in Action 9-2 Interrupting threads
C++ Concurrency in Action 9-2 Interrupting threadsC++ Concurrency in Action 9-2 Interrupting threads
C++ Concurrency in Action 9-2 Interrupting threads
 
2.Startup JavaScript - 연산자
2.Startup JavaScript - 연산자2.Startup JavaScript - 연산자
2.Startup JavaScript - 연산자
 
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
 
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
[D2 COMMUNITY] ECMAScript 2015 S67 seminar - 1. primitive
 
Angular2 가기전 Type script소개
 Angular2 가기전 Type script소개 Angular2 가기전 Type script소개
Angular2 가기전 Type script소개
 
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
KTH_Detail day_화성에서 온 개발자 금성에서 온 기획자 시리즈_5차_데이터분석_조범석_20120613
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료
 
Python Programming: Function
Python Programming: FunctionPython Programming: Function
Python Programming: Function
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary[C++ Korea 2nd Seminar] C++17 Key Features Summary
[C++ Korea 2nd Seminar] C++17 Key Features Summary
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdf
 
C++ 11 에 대해서 쉽게 알아봅시다 1부
C++ 11 에 대해서 쉽게 알아봅시다 1부C++ 11 에 대해서 쉽게 알아봅시다 1부
C++ 11 에 대해서 쉽게 알아봅시다 1부
 
Startup JavaScript 4 - 객체
Startup JavaScript 4 - 객체Startup JavaScript 4 - 객체
Startup JavaScript 4 - 객체
 
Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택Boost라이브러리의내부구조 20151111 서진택
Boost라이브러리의내부구조 20151111 서진택
 
W14 chap13
W14 chap13W14 chap13
W14 chap13
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰
 
Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리Javascript 완벽 가이드 정리
Javascript 완벽 가이드 정리
 

Similar to React로 TDD 쵸큼 맛보기

Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Ji Ung Lee
 
처음배우는 자바스크립트, 제이쿼리 #4
처음배우는 자바스크립트, 제이쿼리 #4처음배우는 자바스크립트, 제이쿼리 #4
처음배우는 자바스크립트, 제이쿼리 #4성일 한
 
Node.js and react
Node.js and reactNode.js and react
Node.js and reactHyungKuIm
 
[ES6] 10. Generator
[ES6] 10. Generator[ES6] 10. Generator
[ES6] 10. GeneratorHan JaeYeab
 
Node.js 현재와 미래
Node.js 현재와 미래Node.js 현재와 미래
Node.js 현재와 미래JeongHun Byeon
 
간단 Ip 필터 구현 이야기
간단 Ip 필터 구현 이야기간단 Ip 필터 구현 이야기
간단 Ip 필터 구현 이야기beom kyun choi
 
C++ Advanced 강의 2주차
C++ Advanced 강의 2주차C++ Advanced 강의 2주차
C++ Advanced 강의 2주차HyunJoon Park
 
Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Kenneth Ceyer
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It종빈 오
 
Startup JavaScript 9 - Socket.IO 실시간 통신
Startup JavaScript 9 - Socket.IO 실시간 통신Startup JavaScript 9 - Socket.IO 실시간 통신
Startup JavaScript 9 - Socket.IO 실시간 통신Circulus
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crowJaeseung Ha
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로Jaeseung Ha
 
처음배우는 자바스크립트, 제이쿼리 #3
처음배우는 자바스크립트, 제이쿼리 #3처음배우는 자바스크립트, 제이쿼리 #3
처음배우는 자바스크립트, 제이쿼리 #3성일 한
 
안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법mosaicnet
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기Chris Ohk
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)Sang Don Kim
 

Similar to React로 TDD 쵸큼 맛보기 (20)

Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2
 
처음배우는 자바스크립트, 제이쿼리 #4
처음배우는 자바스크립트, 제이쿼리 #4처음배우는 자바스크립트, 제이쿼리 #4
처음배우는 자바스크립트, 제이쿼리 #4
 
Swift의 함수와 메소드
Swift의 함수와 메소드Swift의 함수와 메소드
Swift의 함수와 메소드
 
Tdd 4장
Tdd 4장Tdd 4장
Tdd 4장
 
Node.js and react
Node.js and reactNode.js and react
Node.js and react
 
[ES6] 10. Generator
[ES6] 10. Generator[ES6] 10. Generator
[ES6] 10. Generator
 
Node.js 현재와 미래
Node.js 현재와 미래Node.js 현재와 미래
Node.js 현재와 미래
 
간단 Ip 필터 구현 이야기
간단 Ip 필터 구현 이야기간단 Ip 필터 구현 이야기
간단 Ip 필터 구현 이야기
 
C++ Advanced 강의 2주차
C++ Advanced 강의 2주차C++ Advanced 강의 2주차
C++ Advanced 강의 2주차
 
Hacosa j query 10th
Hacosa j query 10thHacosa j query 10th
Hacosa j query 10th
 
HI-ARC PS 101
HI-ARC PS 101HI-ARC PS 101
HI-ARC PS 101
 
Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018Deep dive into Modern frameworks - HTML5 Forum 2018
Deep dive into Modern frameworks - HTML5 Forum 2018
 
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
[WELC] 22. I Need to Change a Monster Method and I Can’t Write Tests for It
 
Startup JavaScript 9 - Socket.IO 실시간 통신
Startup JavaScript 9 - Socket.IO 실시간 통신Startup JavaScript 9 - Socket.IO 실시간 통신
Startup JavaScript 9 - Socket.IO 실시간 통신
 
20150212 c++11 features used in crow
20150212 c++11 features used in crow20150212 c++11 features used in crow
20150212 c++11 features used in crow
 
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
[NDC2015] C++11 고급 기능 - Crow에 사용된 기법 중심으로
 
처음배우는 자바스크립트, 제이쿼리 #3
처음배우는 자바스크립트, 제이쿼리 #3처음배우는 자바스크립트, 제이쿼리 #3
처음배우는 자바스크립트, 제이쿼리 #3
 
안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법안드로이드 설계코드 노하우 및 개발방법
안드로이드 설계코드 노하우 및 개발방법
 
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
[TechDays Korea 2015] 녹슨 C++ 코드에 모던 C++로 기름칠하기
 
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
[Td 2015]녹슨 c++ 코드에 모던 c++로 기름칠하기(옥찬호)
 

React로 TDD 쵸큼 맛보기

  • 2. 김코딩 스마트에디터 3.0, 프론트엔드 개발 - @네이버 기술 블로그(huns.me)에 아주 가끔 글 쓰기 페이스북 커뮤니티 프론트엔드개발그룹 운영하는 척 네이버 사내 리액트 미트업 운영하는 척 Facebook은 React를 왜 만들었을까 - @FBDG 2015 Angular2 vs React, React vs Angular2 - @Deview 2016
  • 3. 오늘의 주제는 … 단위 테스트 어떻게 작성하나요? TDD, 왜 해요? TDD 하면 뭐가 좋아요? TDD 하면 설계를 잘 할 수 있나요? TDD 하면 클린 코드를 작성할 수 있나요? TDD 하는 모습이 궁금해요
  • 4. 오늘의 주제는 … 단위 테스트 어떻게 작성하나요? TDD, 왜 해요? TDD 하면 뭐가 좋아요? TDD 하면 설계를 잘 할 수 있나요? TDD 하면 클린 코드를 작성할 수 있나요? TDD 하는 모습이 궁금해요
  • 5. 오늘 만들 녀석은, “막막” 간단한 Spinbox 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14. it('스핀박스 생성할 수 있다.', () => { // given - 어떤 조건 또는 상황일 때 // when - 어떤 행위를 하면 // then - 결과가 무엇이어야 한다 });
  • 15. it('스핀박스를 생성할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); });
  • 16. it('스핀박스 생성할 수 있다.', () => { // setup // exercise // verify });
  • 17. “어디에서 시작하지?” 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 18. “어디에서 시작하지?” 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 19. it('스핀박스를 생성할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); }); it('스핀박스를 생성할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); }); 복사해서 붙여넣기
  • 20. it('스핀박스를 생성할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); });
  • 21. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); });
  • 22. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { // given // when const spinbox = mount(<Spinbox />); // then const input = spinbox .find('input') .getDOMNode(); expect(input.value).toEqual(200); });
  • 23.
  • 24.
  • 25. import React from 'react'; const Spinbox = () => ( <div> <input type=“text" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox;
  • 26. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox;
  • 27.
  • 28. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { // given // when const spinbox = mount(<Spinbox />); // then const input = spinbox .find('input') .getDOMNode(); const actualValue = Number(input.value); expect(actualValue).toEqual(200); });
  • 29.
  • 30.
  • 31.
  • 32. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox; 넘나 신경 쓰이는 것!
  • 33. TDD는 테스트와 구현을 반복하면서 계단을 하나씩 쌓아가는 여정 “테스트 코드”는 어떻게 검증해야 하지?
  • 34. 두 번째 요구사항 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 35. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { // given // when const spinbox = mount(<Spinbox />); // then const input = spinbox .find('input') .getDOMNode(); const actualValue = Number(input.value); const defaultValue = 200; expect(actualValue).toEqual(defaultValue); });
  • 36. it('입력 폼에 999를 입력할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then const input = spinbox .find('input') .getDOMNode(); const actualValue = Number(input.value); const defaultValue = 200; expect(actualValue).toEqual(defaultValue); });
  • 37. it('입력 폼에 999를 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '999' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); });
  • 38.
  • 39. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox;
  • 40. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" onChange={ () => { this.setState({ value: 999 }) } } /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox; 아놬! 무상태 컴포넌트!
  • 41.
  • 42. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox; 안전할 때 까지 되돌리기!
  • 43.
  • 44. it('입력 폼에 숫자 값을 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '999' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); });
  • 45. it.skip('입력 폼에 숫자 값을 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '999' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); });
  • 46.
  • 47. import React from 'react'; const Spinbox = () => ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox;
  • 48. import React from ‘react'; class Spinbox extends React.Component { render() { return ( <div> <input type="text" defaultValue="200" /> <button>▲</button> <button>▼</button> </div> ); } } Spinbox.defaultProps = {}; Spinbox.propTypes = {}; export default Spinbox;
  • 49.
  • 50. it.skip('입력 폼에 숫자 값을 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '999' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); });
  • 51. it('입력 폼에 999를 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '999' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); });
  • 52.
  • 53. class Spinbox extends React.Component { componentWillMount() { this.state = { value: 200 }; } render() { return ( <div> <input type="text" value={ this.state.value } onChange={ () => { this.setState({ value: 999 }) } } /> <button>▲</button> <button>▼</button> </div> ); } } // 생략 …
  • 54.
  • 55.
  • 56. class Spinbox extends React.Component { componentWillMount() { this.state = { value: 200 }; } render() { return ( <div> <input type="text" value={ this.state.value } onChange={ () => { this.setState({ value: 999 }) } } /> <button>▲</button> <button>▼</button> </div> ); } }
  • 57. class Spinbox extends React.Component { componentWillMount() { this.state = { value: 200 }; this.handleChangeInput = this.handleChangeInput.bind(this); } render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button>▲</button> <button>▼</button> </div> ); } handleChangeInput() { this.setState({ value: 999 }); } }
  • 58. it('스핀박스를 생성할 수 있다.', () => { // given // when const spinbox = mount(<Spinbox />); // then expect(spinbox).toBeDefined(); }); it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … }); it('입력 폼에 999를 입력할 수 있다.', () => { … });
  • 59. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … }); it('입력 폼에 999를 입력할 수 있다.', () => { … });
  • 60. it('입력 폼에 0을 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '0' } }); // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(0); });
  • 61.
  • 64.
  • 65.
  • 66. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { // given // when const spinbox = mount(<Spinbox />); // 생략… }); it('입력 폼에 999를 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // 생략… }); it('입력 폼에 0을 입력할 수 있다.', () => { // given const spinbox = mount(<Spinbox />); // 생략… });
  • 67. let spinbox; beforeEach(() => { spinbox = mount(<Spinbox />); }); it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … }); it('입력 폼에 999를 입력할 수 있다.', () => { … }); it('입력 폼에 0을 입력할 수 있다.', () => { … });
  • 68.
  • 69. it('입력 폼에 999을 입력할 수 있다.', () => { // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(999); }); it('입력 폼에 0을 입력할 수 있다.', () => { // then const inputNode = input.getDOMNode(); const actualValue = Number(inputNode.value); expect(actualValue).toEqual(0); });
  • 70. let spinbox; beforeEach(() => { spinbox = mount(<Spinbox />); }); function getValueFromInputNode(input) { const inputNode = input.getDOMNode(); return Number(inputNode.value); } it('입력 폼에 999를 입력할 수 있다.', () => { // …생략 // then const actualValue = getValueFromInputNode(input); expect(actualValue).toEqual(999); }); it('입력 폼에 0을 입력할 수 있다.', () => { // …생략 // then const actualValue = getValueFromInputNode(input); expect(actualValue).toEqual(0); });
  • 71.
  • 72. 세 번째 요구사항 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 73. it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { // given // when const input = spinbox.find('input'); input.simulate('change', { target: { value: '0' } }); // then const actualValue = getValueFromInputNode(input); expect(actualValue).toEqual(0); });
  • 74. it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { // given const defaultValue = 200; // when const incrementBtn = spinbox.find('[data-name="increment"]'); incrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue + 1); });
  • 75.
  • 76. render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment">▲</button> <button>▼</button> </div> ); }
  • 77.
  • 78. render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment" onClick={ () => { this.setState({ value: 201 }) } }>▲</button> <button>▼</button> </div> ); }
  • 79.
  • 80.
  • 81. render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment" onClick={ () => { this.setState({ value: 201 }) } }>▲</button> <button>▼</button> </div> ); }
  • 82. componentWillMount() { this.state = { value: 200 }; this.handleChangeInput = this.handleChangeInput.bind(this); this.handleClickIncrement = this.handleClickIncrement.bind(this); } render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment" onClick={ this.handleClickIncrement }>▲</button> <button>▼</button> </div> ); } handleClickIncrement() { this.setState({ value: 201 }); }
  • 83.
  • 84. it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { // given const defaultValue = 200; // when const incrementBtn = spinbox.find('[data-name="increment"]'); incrementBtn.simulate('click'); incrementBtn.simulate('click'); incrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue + 3); });
  • 85.
  • 88.
  • 89.
  • 90. it('스핀박스를 생성하면 기본값은 200이어야 한다.', () => { … }); it('입력 폼에 999를 입력할 수 있다.', () => { … }); it('입력 폼에 0을 입력할 수 있다.', () => { … }); it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … }); it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … });
  • 91. describe('기본값 >', () => { it('스핀박스를 생성하면 기본값이 200이어야 한다.', () => { … }); }); describe('값 입력 >', () => { it('입력 폼에 999를 입력할 수 있다.', () => { … }); it('입력 폼에 0을 입력할 수 있다.', () => { … }); }); describe('값 증가 >', () => { it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … }); it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … }); });
  • 92.
  • 93. describe(‘값 입력 >', () => { it('입력 폼에 999를 입력할 수 있다.', () => { // given // when const input = spinbox.find('input'); // … 생략 }); it('입력 폼에 0을 입력할 수 있다.', () => { // given // when const input = spinbox.find('input'); // … 생략 }); });
  • 94. describe(‘값 입력 >', () => { let input; beforeEach(() => { input = spinbox.find('input'); }); it('입력 폼에 999를 입력할 수 있다.', () => { … }); it('입력 폼에 0을 입력할 수 있다.', () => { … }); });
  • 95.
  • 96. describe(‘기본값 >', () => { it('스핀박스를 생성하면 기본값이 200이어야 한다.', () => { … }); }); describe('값 입력 >', () => { let input; beforeEach(() => { input = spinbox.find('input'); }); it('입력 폼에 999를 입력할 수 있다.', () => { … }); it('입력 폼에 0을 입력할 수 있다.', () => { … }); }); describe('값 증가 >', () => { const defaultValue = 200; let incrementBtn; beforeEach(() => { incrementBtn = spinbox.find('[data-name="increment"]'); }); it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { … }); it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { … }); });
  • 97.
  • 98. 얻는 것과 잃는 것 변경의 포인트는 집중 코드는 덜 직관적 it('증가 버튼을 세 번 클릭하여 값을 3 증가시킬 수 있다.', () => { // given // when incrementBtn.simulate('click'); incrementBtn.simulate('click'); incrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue + 3); }); 뭘까?
  • 99. 네 번째 요구사항 기본값은 200 값 입력 증가 버튼을 클릭하여 값이 1 증가 감소 버튼을 클릭하면 값이 1 감소
  • 100. describe('값 증가 >', () => { const defaultValue = 200; let incrementBtn; beforeEach(() => { incrementBtn = spinbox.find('[data-name="increment"]'); }); it('증가 버튼을 클릭하여 값을 1 증가시킬 수 있다.', () => { // given // when incrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue + 1); }); });
  • 101. describe('값 감소 >', () => { const defaultValue = 200; let decrementBtn; beforeEach(() => { decrementBtn = spinbox.find('[data-name="decrement"]'); }); it('감소 버튼을 클릭하여 값을 1 감소시킬 수 있다.', () => { // given // when decrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue - 1); }); });
  • 102.
  • 103. class Spinbox extends React.Component { componentWillMount() { this.state = { value: 200 }; this.handleChangeInput = this.handleChangeInput.bind(this); this.handleClickIncrement = this.handleClickIncrement.bind(this); this.handleClickDecrement = this.handleClickDecrement.bind(this); } render() { … } handleClickDecrement() { this.setState({ value: this.state.value - 1 }); } handleClickIncrement() { … } handleChangeInput(e) { … } }
  • 104. render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment" onClick={ this.handleClickIncrement }>▲</button> <button>▼</button> </div> ); }
  • 105. render() { return ( <div> <input type="text" value={ this.state.value } onChange={ this.handleChangeInput } /> <button data-name="increment" onClick={ this.handleClickIncrement }>▲</button> <button data-name="decrement" onClick={ this.handleClickDecrement }>▼</button> </div> ); }
  • 106.
  • 107.
  • 109. it('감소 버튼을 세 번 클릭하여 값을 3 감소시킬 수 있다.', () => { // given // when decrementBtn.simulate('click'); decrementBtn.simulate('click'); decrementBtn.simulate('click'); // then const actualValue = getValueFromInputNode(spinbox.find('input')); expect(actualValue).toEqual(defaultValue - 3); });
  • 110.