초보 개발자의 일기

테스트 코드란 본문

Frontend practice/React

테스트 코드란

판다꼬마 2024. 2. 13. 21:49
728x90

테스트코드란?

 

1. 테스트 코드의 작성의 목적

  • 정확성 및 신뢰성 확보
    • 테스팅의 주요 목적은 코드가 올바르게 작동하는지 확인하는 것이다.
    • 다양한 조건 및 입력에서 React 컴포넌트와 코드가 예상대로 작동하는지 확인한다.
  • 수월한 리팩토링
    • 프로젝트가 성장하면 리팩토링이 필요하다
    • 리팩토링 전 테스트코드를 작성하면 최소한의 기준이 만들어진다.
    • 변경사항 또는 최적화가 예상치 못한 버그를 초래하지 않도록 한다.

 

2. 테스트 코드의 작성의 장점

  • 문서화 및 이해
    • 명확하게 작성된 테스트 코드는 문서의 형태를 이룬다.
      • 내가 작성한 코드가 기획의도를 확실히 반영하는지 확인 가능
      • 기획 내용을 잘 반영하였는지 확인 가능
      • 기획자와의 소통의 도구로도 사용할 수 있다.
      • 다른 개발자들이 테스트코드를 보고 컴포넌트나 함수의 예상되는 동작을 쉽게 이해할 수 있다.
describe("회원가입 페이지", () => {

  test("인풋이 활성화되면 underline의 컬러가 바뀐다", async () => {  });
  test("아이디가 중복이면 에러메시지가 나타난다", async () => {  });
  test("비밀번호가 일치하지 않으면 에러메시지가 나타난다", async () => {  });
  test("회원가입에 실패하면 에러메세지가 나타난다", async () => {  });
});

 

 

3. 테스트해야하는 것들

  • 테스트 코드의 목적
    • 코드가 올바르게 작동하는지 확인을 하기 위해 작성
    • 브라우저에서 내가 작성한 코드가 잘 동작하는지 확인을 하기 위해 작성
  • 테스트 해야 할 항목들
    • 비지니스 로직
      • 코드가 잘 동작하는지 확인하기 위한 테스트이다.
      • 버튼을 클릭했을 때 내가 의도한 대로 작동을 하는가 테스트해야 한다.
        • 로그인 성공 시 내가 원하는 화면으로 redirect 되는지 확인
        • 로그인 실패 시 내가 원하는 에러메시지가 잘 나오는지 확인
  • 테스트 안 해도 되는 것들
    • 여러 input 간의 margin, padding 같은 것은 테스트를 안 해도 된다.
      • why?  반응형으로 화면을 설계하기 때문에 반응형을 고려해야 하기 때문

 

1. 유닛테스트

가장 작은 단위의 테스트이다.

 

ex) 로그인 화면

  • input이나 button들이 잘 렌더링 되는지 확인한다.
  • 이메일 input 값이 잘 변경되는지 확인한다.
  • 버튼을 클릭하면 로그인이 잘 되는지 확인한다.
  • 비밀번호를 입력할 때 설정한 규칙에 잘 맞는지 확인한다.

2. 통합테스트

다양한 컴포넌트, 모듈, 함수들이 잘 연결되었는지 확인하는 테스트

 

ex) 로그인 화면

  • 로그인 버튼을 클릭하고, 로그인 성공 시 원하는 화면으로 잘 redirect 되는지 확인해 본다.
  • 로그인을 실패하면 별도로 선언한 modal이 잘 나타나는지 확인한다.

3. E2E테스트

실제 사용자가 접근해서 이용하는 것처럼 테스트

 

ex) 로그인 화면

  • 사용자 입장에서 전체적인 로그인 전체 흐름을 테스트해 본다.

4. 일반적으로...

일반적으로는 유닛테스트, 통합테스트는 jest로 작성

E2E 테스트는 cypress를 활용한다.


1. 테스트 코드 문법 소개

  • It (아니면 test)
    • 실제 테스트 코드를 작성하는 함수
    • 테스트 코드가 어떤 역할을 하는지 작성하는 곳
    • 테스트 명을 문장으로 작성해서 하나의 문장이 되는 형식

 

it('should render username and password input fields', () => {
    const { getByPlaceholderText } = render(<Login />);
    
    const usernameInput = getByPlaceholderText('Username');
    const passwordInput = getByPlaceholderText('Password');

    expect(usernameInput).toBeInTheDocument();
    expect(passwordInput).toBeInTheDocument();
  });
test('계정 정보를 입력할 수 있는 input들이 화면에 나타난다', () => {
    const { getByPlaceholderText } = render(<Login />);
    
    const usernameInput = getByPlaceholderText('Username');
    const passwordInput = getByPlaceholderText('Password');

    expect(usernameInput).toBeInTheDocument();
    expect(passwordInput).toBeInTheDocument();
  });
  • describe
    • it이나 test들의 묶음이다.
    • 관련 있는 테스트를 하나로 묶는다 =>  응집도를 높일 수 있음
describe('Login Component', () => {
  it('should render username and password input fields', () => {
    const { getByPlaceholderText } = render(<Login />);
    
    const usernameInput = getByPlaceholderText('Username');
    const passwordInput = getByPlaceholderText('Password');

    expect(usernameInput).toBeInTheDocument();
    expect(passwordInput).toBeInTheDocument();
  });

  it('should call authenticateUser service with entered credentials on login button click', async () => {
// 다른 테스트 코드
  });

  it('should display an error message if login attempt fails', async () => {
    mockAuthenticateUser.mockRejectedValue(invalidCredentialsError);

    const { getByPlaceholderText, getByText } = render(<Login />);

    const usernameInput = getByPlaceholderText('Username');
    const passwordInput = getByPlaceholderText('Password');
    const loginButton = getByText('Login');

    fireEvent.change(usernameInput, { target: { value: 'wronguser' } });
    fireEvent.change(passwordInput, { target: { value: 'wrongpass' } });
    fireEvent.click(loginButton);

		const invalidCredentialsError = new Error('Invalid credentials');
    const errorMessage = await getByText(invalidCredentialsError.message);

    expect(errorMessage).toBeInTheDocument();
  });

});
  • beforeEach
    • describe 블록 안에 있는 각각의 it 작동 전에 동작하는 함수
    • 테스트 환경이나 테스트 케이스를 설정하는데 좋다.
  • beforeAll
    • 각 describe 전에 작동되는 함수
    • 테스트들이 공통으로 사용하는 configuration이나 상수들을 선언하는데 활용된다.
describe('UserProfile Component', () => {
  let user;

  beforeAll(() => {
    user = {
      id: 1,
      name: 'John Doe',
      email: 'john.doe@example.com'
    };
  });
  • afterEach
    • describe 블록 안에 있는 각각의 it 작동 후에 동작하는 함수
    • mock data를 clean up 할 때 사용, configuration를 초기화할 때 사용
  • afterAll
    • 각 descirbe 후에 작동되는 함수
    • 여러 개의 describe에 공통으로 사용되는 것들을 초기화할 때 좋다.
  afterAll(() => {
    user = null;
  });
728x90