-
Notifications
You must be signed in to change notification settings - Fork 27
Week3 기술공유 : [빠르게 훓어보는 Testing React App]
Sungdong Jo edited this page Dec 21, 2019
·
2 revisions
조성동
(* React 기준)
-
단위 테스트 : 하나의 컴포넌트를 테스트
- ex 1. state 값 변경 확인
- ex 2. DOM check (HTML 태그, CSS style)
-
통합 테스트 : 여러 컴포넌트들이 협력하는 동작을 테스트
- ex 1. 부모 A 컴포넌트가 자식인 B 컴포넌트로 props를 잘 전달했는지
- ex 2. state 변화에 따라 렌더링이 변경될 부분이 렌더링이 되었는지
-
E2E(End 2 End) 테스트 : 사용자 입장에서(실제 웹페이지) 컴포넌트들의 동작을 테스트
- ex 1. Header의 존재 여부
- ex 2. 버튼을 눌렀을 때 팝업의 열림 여부
- 마크업 및 스타일(색상, 크기, 여백, 커서 ...), 출력되는 텍스트, ... (너무 많다.)
- Props, State
- Event
// Button.tsx
function Btn({
content,
href,
to,
styletype = 'primary',
...props
}: Props): React.ReactElement {
if (to) {
return (
// react-router-dom/Link
<S.StyledLink styletype={styletype} to={to} {...props}>
{content}
</S.StyledLink>
);
}
if (href) {
return (
// a tag
<S.Anchor styletype={styletype} href={href} {...props}>
{content}
</S.Anchor>
);
}
return (
// button tag
<S.StyledBtn styletype={styletype} {...props}>
{content}
</S.StyledBtn>
);
describe("Atom / Btn", () => {
it("[PROPS] disabled", () => {
// given
const wrapperIsDisabled = mount(<Btn disabled={true}>iambutton</Btn>);
const wrapperIsNotDisabled = mount(<Btn disabled={false}>iambutton</Btn>);
// then
expect(wrapperIsDisabled.prop("disabled")).toBe(true);
expect(wrapperIsDisabled).toHaveStyleRule("cursor", "default");
expect(wrapperIsDisabled).toHaveStyleRule("pointer-events", "none");
expect(wrapperIsNotDisabled.prop("disabled")).toBe(false);
expect(wrapperIsNotDisabled).toHaveStyleRule("cursor", "pointer");
expect(wrapperIsNotDisabled).toHaveStyleRule("pointer-events", "auto");
});
});
describe("Example state", () => {
it("set and assert", () => {
// given
const wrap = shallow(<Component />);
wrap.setState({ show: true });
// then
expect(wrap.state("show")).toEqual(true);
});
});
describe("Atom / Btn", () => {
it("[EVENT] click", () => {
const wrapper = mount(<Btn styletype="alert" />);
// Btn 내부에 정의된 onClick이 호출
wrapper.find("button").simulate("click");
// do something...
});
});
이전에 촬영한 성공적인 컴포넌트 UI과 현재의 컴포넌트 UI를 비교한다. = 최종 마크업 비교
describe("Atom / Btn", () => {
it("[SNAPSHOT] StyledBtn", () => {
// given
const wrapper = mount(<Btn styletype={"primary"} />);
// then
expect(wrapper).toMatchSnapshot(); 📸
});
});
// seed.spec.ts
// written by @FullOfOrange, @dobest27
describe("DB seed 데이터가 유효", () => {
it("User 데이터가 유효", async () => {
//given, when
const users = await User.findAll({
attributes: { exclude }
});
//then
expect(users).toMatchSnapshot();
});
});
- 테스트 작성 비용을 크게 줄인다.
- TDD를 할 수 없다.
- snapshot를 업데이트 하고 싶은 유혹이 있다. (테스트를 쉽게 통과할 수 있다.) 😏
- UI는 정적이지 않다.
- 자주 수정이 되지 않는 컴포넌트일 때
- 너무 복잡하지 않은 컴포넌트일 때
ex. atomic component...
- 전부 다 테스트를 하자니 너무 많습니다(그리고 시간도 없습니다).
- 세세한 테스트는 공감을 이끌어내지 못합니다. (노력 대비 쓸모가 없어보이기도 합니다.)
실용적인 리액트 테스트 전략
DevOps
Infra Structure
컴포넌트 작성법
Client Sturcture
데이터베이스 스키마
Yarn workspace 명령어
Docker를 이용한 서버 개발 환경
Linting Tools