front-end에서 TDD로 테스트 코드를 작성하면서 많은 고민을 했다.
위 질문에 대한 궁금증을 해결하기 위해 검색하다가 BDD에 대해 알게 되었고, 가장 정답에 가까운 느낌을 받았다.
BDD(Behavior Driven Development)는 행동 주도 개발하는 방법이다.
즉, 프론트엔드에서는 사용자가 웹 페이지에서 버튼 클릭, 입력, 드래그 등 다양한 동작을 수행하고 난 후, 웹 페이지의 상태를 테스트 케이스로 작성하는 것이라고 생각한다.
테스트 코드를 작성하는 방법은 자유지만, BDD에서는 기본적으로 템플릿이있다.
GIVEN ( 처음 상태 )
WHEN ( 결과를 만들기 위한 행위 )
THEN ( 결과 )
위 템플릿은 기본적으로 BDD 테스트 코드를 쉽게 작성하기 위한 템플릿일 뿐!! 꼭 지켜야한다고 생각하지 않고 해외 개발자들도 그렇게 말하고 있다.
첫번째 ) InputText 컴포넌트 렌더링에 대한 BDD 테스트 케이스
InputText.test.jsx
를 작성한다. test('InputText 컴포넌트가 렌더링 되어야한다.', () => {
//GIVEN
render(<InputText />);
//WHEN
//THEN
expect(screen.getByRole('textbox')).toBeInTheDocument();
});
InputText.jsx
를 작성한다.export const InputText = () => {
return <input type="text" />;
};
위 테스트 케이스는 특별한 행위WHEN
에 대한 코드없이 쉽게 결과를 만들 수 있기 때문에 WHEN
을 작성하지 않았다. BDD 템플릿은 그냥 템플릿일 뿐 무조건 지키지 않아도 된다.
두번째 ) InputText 컴포넌트에 데이터 입력에 대한 테스트 케이스
InputText.test.jsx
를 작성한다. test('InputText에 데이터를 입력하면 value값이 변경이 되어야한다.', () => {
//GIVEN
render(<InputText />);
//WHEN
//THEN
expect(screen.getByRole('textbox'))
});
InputText.jsx
를 작성한다.export const InputText = () => {
return <input type="text" />;
};
InputText
의 테스트 시나리오에 대한 WHEN
, THEN
작성 test('InputText에 데이터를 입력하면 value값이 변경이 되어야한다.', () => {
//GIVEN
render(<InputText />);
const inputBox = screen.getByRole('textbox');
//WHEN
fireEvent.change(inputBox, { target: { value: 'BDD테스트' } });
//THEN
expect(screen.getByRole('textbox')).toHaveValue('BDD테스트');
});
input Tag
에 데이터를 입력하면 Value에 입력되기 때문에 추가적으로 코드를 작성하지 않아도 된다. 그렇다면 Custom Input Compoent를 예시로 들어보겠다.
세번째 ) Custom Input 컴포넌트에서 props로 value, onChange가 사용될 경우
InputText.test.jsx
를 작성한다. test('Custom InputText에 데이터를 입력하면 value값이 변경이 되어고, 변경된 데이터가 onChange로 callback 함수로 데이터를 받는다', () => {
const handleChange = jest.fn();
//GIVEN
render(<InputText value="초기 데이터" onChange={handleChange} />);
//WHEN
//THEN
expect(screen.getByRole('textbox'));
});
InputText.jsx
를 작성한다.export const InputText = (props: InputTextProps) => {
return <input type="text" />;
};
InputText
의 테스트 시나리오에 대한 WHEN
, THEN
작성test('Custom InputText에 데이터를 입력하면 value값이 변경이 되고, 변경된 데이터가 onChange로 callback 함수로 데이터를 반환한다.', () => {
const handleChange = jest.fn();
//GIVEN
render(<InputText value="초기 데이터" onChange={handleChange} />);
const inputBox = screen.getByRole('textbox');
expect(inputBox).toHaveValue('초기 데이터');
//WHEN
fireEvent.change(inputBox, { target: { value: 'BDD테스트' } });
//THEN
expect(handleChange).toHaveBeenCalledTimes(1);
expect(handleChange).toHaveBeenCalledWith('BDD테스트');
});
WHEN
, THEN
에 대한 InputText
컴포넌트 작성export const InputText = (props) => {
return (
<input
type="text"
value={props.value}
onChange={(e) => props.onChange(e.target.value)}
/>
);
};
위 예제 처럼 테스트 코드를 먼저 작성하고, 테스트 코드로 인해 발생한 오류를 최소한의 코드로 해결하기를 반복하며 테스트 시나리오를 작성한다.
어찌보면 TDD라고 생각할 수 있지만, BDD는 TDD와 많이 다르지 않다. 오히려 BDD는 추상적인 TDD를 구체화한 개발 방법론이라고 생각하면 될 거 같다.
이것 말고도 행위에 대한 css style
변화에 대한 테스트 코드도 작성할 수 있고, 렌더링시 server로 부터 data fetch
후 화면의 상태 등... BDD를 알고 나서 언제 어떨 때 테스트 코드를 작성해야 할지 명확해졌다.
무슨 기준으로 작성해야하나?
ㄴ 클라이언트의 행동(행위)의 결과를 테스트
그냥 단순히 렌더링만 하는건데 테스트해야하나?
ㄴ 정말 많이 고민했다.
ㄴ 결론적으로 해야한다.
ㄴ 그러면 예시로 어디서 해야할까? 약관
및 조금이라도 변경되면 안되는분
이라면 무조건 해야한다.
참고 자료
https://medium.com/@paulallies/bdd-style-of-tdd-with-jest-react-and-react-hooks-9eb68916efe8
https://medium.com/javascript-scene/behavior-driven-development-bdd-and-functional-testing-62084ad7f1f2