Skip to content

Conversation

@timothypark33
Copy link

@timothypark33 timothypark33 commented Dec 14, 2021

안녕하세요 이번에 처음으로 jest를 배워보고 테스트 코드를 작성해보았습니다.

질문은 fileChanged에 추가하겠습니다.

감사합니다.

진도

  • Input 컴포넌트 테스트 작성
  • Item 컴포넌트 테스트 작성
  • List 컴포넌트 테스트 작성
  • Page 컴포넌트 테스트 작성
  • App 컴포넌트 테스트 작성
  • index.jsx 테스트 작성
  • 모든 컴포넌트에 테스트를 작성
  • 커버리지 100% 달성하기

Copy link
Collaborator

@moonkii moonkii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

테스트 코드 작성이 처음이시면 익숙하지 않을거에요.
하다보면 대략적인 패턴이 있기 때문에 강의에 나온 내용들을 반복해서 연습해보시면 좋아요!

fireEvent.click(getByText('추가'));
expect(handleClick).toBeCalled();

expect(getByRole('textbox').value).toBe('test');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getByRole 을 사용하신 이유가 있나요?

@timothypark33
Copy link
Author

올려주신 것에서 답글이 안달려서 여기에 적습니다!
1.Input으로 수정하고 it보다 test로 일관되게 적으려고 test로 수정했습니다
2. <input type="text" ... > 태그 안에있는 value 값을 가져오려고 getByRole을 사용했습니다. getByPlaceholder보다
3.큰 의도가 없습니다..toBeCalled로 수정했습니다.

@moonkii
Copy link
Collaborator

moonkii commented Dec 15, 2021

1.Input으로 수정하고 it보다 test로 일관되게 적으려고 test로 수정했습니다

테스트를 작성하실 때 test 를 사용할 수도 있지만
좀 더 구체적이고 서술적인 테스트 시나리오 작성을 위해 describe ~ context ~ it 구조를 사용해주면 좋아요.

describe 는 테스트 주체가 되는 서술 대상이에요.
context 는 따로 비교해줘야할 맥락(상황)이 있을 때만 선택적으로 사용해요.
it 은 실제로 테스트할 내용을 서술해요. 여기서 itdescribe 에서 작성한 서술대상이에요. (주로 컴포넌트겠죠?)

  1. <input type="text" ... > 태그 안에있는 value 값을 가져오려고 getByRole을 사용했습니다. getByPlaceholder보다

getByText 같은걸 사용해볼 수도 있을거에요 ;)

@timothypark33
Copy link
Author

timothypark33 commented Dec 16, 2021

  1. <input type="text" ... > 태그 안에있는 value 값을 가져오려고 getByRole을 사용했습니다. getByPlaceholder보다

getByText 같은걸 사용해볼 수도 있을거에요 ;)

input태그를 선택하기위해서 getByText를 어떻게 정말 사용할지 모르겠습니다...
https://testing-playground.com/
에서 input태그를 선택할때에 아래 4가지 중에서 Text는 값이 비어있어서 불가능한걸로 알고있었습니다..
image

차선책으로 getByLabelText로 사용해보도록하겠습니다.ㅜㅜ...

@timothypark33
Copy link
Author

timothypark33 commented Dec 18, 2021

리뷰

주어진 피드백 잘 반영했습니다 피드백으로 향상되어감이 느껴집니다. 감사합니다.
테스트 코드 이번에 처음 해보는데 솔직히 제대로 하고있나 의문은 정말 많았습니다.
뭘 질문해야할 지도 모르겠었고 잘못 짚었었는데 그래도 피드백 주셔서 여기까지 완성할 수 있었습니다.

그런데 저희가 1-2주차에서 사용한 테스트 코드는 codeceptjs를 사용하셨던데
다음 주차 과제에서 테스트 코드 작성시 codeceoptjs까지 사용하는게 좋을까요??

src/App.test.jsx Outdated
expect(getByLabelText('할 일').value).toBe('');
});

it('할 일을 추가하고 모두 삭제하면 "할 일이 없어요!"가 뜬다. ', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 핵심으로 확인하고 싶은게 무엇일까요?
그걸 테스트 시나리오에 드러내주면 좋을 것 같아요.

Comment on lines 21 to 40
const { getByLabelText } = InputComponent();
expect(getByLabelText('할 일')).toHaveAttribute('value', value);
});

it('추가 버튼이 작동한다.', () => {
const { getByText } = InputComponent();
expect(handleClick).not.toBeCalled();
fireEvent.click(getByText('추가'));
expect(handleClick).toBeCalled();
});

it('textbox에 값이 입력된다.', () => {
const { getByLabelText } = InputComponent();
expect(handleChange).not.toBeCalled();
fireEvent.change(getByLabelText('할 일'), {
target: {
value: 'test2',
},
});
expect(handleChange).toBeCalled();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의미상으로 구분되는 경우 빈 줄을 넣어서 구분해주면 코드 가독성이 더 좋을 것 같아요!


const value = 'test';

const InputComponent = () => render(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 역할을 하는지 함수의 이름을 더 명확하게 해줄 수 있을까요?

Comment on lines 12 to 17
const ListComponent = (task) => render(
<List
tasks={task}
onClickDelete={handleClick}
/>,
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const ListComponent = (task) => render(
<List
tasks={task}
onClickDelete={handleClick}
/>,
);
const ListComponent = (task) => render((
<List
tasks={task}
onClickDelete={handleClick}
/>
));

괄호로 두 번 감싸주면 콤마를 없앨 수 있어요!

{ id: 101, title: '물 마시기' },
];

const ListComponent = (task) => render(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트를 render 해주는 함수는 describe 내부에 있는게 좋아요.

{ id: 100, title: '숨 쉬기' },
]);

context('언제든지', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 제거해줘도 될 것 같아요.

@moonkii
Copy link
Collaborator

moonkii commented Dec 18, 2021

그런데 저희가 1-2주차에서 사용한 테스트 코드는 codeceptjs를 사용하셨던데
다음 주차 과제에서 테스트 코드 작성시 codeceoptjs까지 사용하는게 좋을까요??

인수테스트는 아마 미리 작성되어 있을거에요.
원래는 인수테스트 -> 단위 테스트 순으로 작성하는데 지금 과제에서는 단위 테스트에 좀 더 초점맞춰서 진행하고 있어요 ;)

expect(handleClick).toBeCalled();
});

it('textbox에 값이 입력된다.', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

값이 입력되는 것 보다는 handleChange 함수가 호출되는게 핵심인 것 같아요.

{ id: 101, title: '물 마시기' },
];

const renderComponent = (task) => render((
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 컴포넌트를 render 해주는지 구체적으로 이름을 지어주시면 좋을 것 같아요.
만약에 저라면 renderList 정도로 표현했을 것 같아요 ;)

Comment on lines 6 to 9
given('noTask', () => []);
given('tasks', () => [
{ id: 100, title: '숨 쉬기' },
]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

task 는 하나의 변수로 관리해주면 좋을 것 같아요.

Comment on lines 20 to 35
context('List에게 task가 없을 떄', () => {
it('"할 일이 없어요"를 그린다.', () => {
const { container } = render(<Page tasks={given.noTask} />);

expect(container).toHaveTextContent('할 일이 없어요!');
});
});

context('List에게 task가 있을 때', () => {
it('task를 그린다.', () => {
const { container, getAllByText } = render(<Page tasks={given.tasks} />);

expect(container).toHaveTextContent(given.tasks[0].title);
expect(getAllByText('완료')[0]).toContainHTML('button');
});
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
context('List에게 task가 없을 떄', () => {
it('"할 일이 없어요"를 그린다.', () => {
const { container } = render(<Page tasks={given.noTask} />);
expect(container).toHaveTextContent('할 일이 없어요!');
});
});
context('List에게 task가 있을 때', () => {
it('task를 그린다.', () => {
const { container, getAllByText } = render(<Page tasks={given.tasks} />);
expect(container).toHaveTextContent(given.tasks[0].title);
expect(getAllByText('완료')[0]).toContainHTML('button');
});
});
context('List에게 task가 없을 떄', () => {
given('tasks', () => []);
it('"할 일이 없어요"를 그린다.', () => {
const { container } = render(<Page tasks={given.noTask} />);
expect(container).toHaveTextContent('할 일이 없어요!');
});
});
context('List에게 task가 있을 때', () => {
given('tasks', () => {
id: 100,
title: '할 일',
});
it('task를 그린다.', () => {
const { container, getAllByText } = render(<Page tasks={given.tasks} />);
expect(container).toHaveTextContent(given.tasks[0].title);
expect(getAllByText('완료')[0]).toContainHTML('button');
});
});

given 을 context 에 따라 활용한다면 이런 형태가 될거에요.

@timothypark33
Copy link
Author

일요일날 마지막까지 리뷰 정말 감사합니다.
반복제거
핵심 시나리오 작성
task는 최소한
given 사용법
모두 잘 이해할 수 있었습니다.

@moonkii moonkii merged commit 5d06c1e into CodeSoom:GUAJEGUICHAN Dec 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants