[CodeStates-Section4]U7.Testing-TDD

hameee·2023년 1월 31일
0

CodeStates_Frontend_42기

목록 보기
38/39
post-thumbnail

후기

이번 챕터를 통해 Mocha, Jest, Chai, Testing Library 등 다양한 프레임워크와 라이브러리를 접해볼 수 있었다. 각각의 공식 문서를 파고, 프레임워크와 라이브러리의 개념이 헷갈려 개념을 파고, 갑자기 이제까지 배운 프로그램들은 라이브러리였나, 프레임워크였나, 둘 다 아니라면 무엇이었나 확실히 하고 싶어 강의 자료와 블로그를 계속 뒤적거린 하루였다. 당장의 진도를 이해하기 급급하다 보니 전체적인 그림을 그려볼 기회가 부족했는데, 오늘 학습으로 머릿속에서 정리가 된 것 같다.

<Chapter1. TDD>
-1. TDD 방법론
<Node/Browser와 TDD>
-1. JS(if, throw) + Mocha(it)
-2. Mocha(it) + Chai(assert)
-3. Mocha(it) + Chai(expect)
-4. Mocha(it) + Chai(should)
-5. Mocha(describe, it) + Chai(expect)
<React와 TDD>
-1. Jest & Testing Library
-2. React 프로젝트 생성 시 내장된 테스트 관련 라이브러리
-3. 사용 예시

<Chapter1. TDD>

1.TDD 방법론

1) 정의

Test-Driven-Development, 테스트 주도 개발
코드를 작성하기 전에 테스트를 쓰는 소프트웨어 개발 방법론
바람직하다고 생각하는 코드 결과 미리 정의 -> 이것을 바탕으로 코드 작성

2) TDD의 개발 주기

① Write Failing Test: 실패하는 테스트 코드를 먼저 작성
② Make Test Pass: 테스트 코드를 성공시키기 위한 실제 코드를 작성
③ Refactor: 중복 코드 제거, 일반화 등의 리팩토링을 수행

3) TDD를 사용하는 이유

예상하지 못했던 버그를 줄여 소요 시간을 줄일 수 있음
불필요한 설계 피할 수 있음

<Node/Browser와 TDD>

-> Mocha(프레임워크) + Chai(라이브러리)

1.JS(if, throw) + Mocha(it)

it('has a prefix of 4 and a length of 13', function () {
  if (detectNetwork('4123456789012') !== 'Visa') {
    throw new Error('Test failed');
  }
});

2.Mocha(it) + Chai(assert)

let assert = chai.assert.isTrue;

it('has a prefix of 4 and a length of 13', function () {
  assert(detectNetwork('4123456789012') === 'Visa');
});

3.Mocha(it) + Chai(expect)

let expect = chai.expect;

it('has a prefix of 4 and a length of 13', function () {
  expect(detectNetwork('4123456789012')).to.equal('Visa');
});

4.Mocha(it) + Chai(should)

let should = chai.should(); // ❗️should 실행

it('has a prefix of 4 and a length of 13', function () {
  detectNetwork('4123456789012').should.equal('Visa');
});

5.Mocha(describe, it) + Chai(expect)

-> describe로 it 메소드 여러 개 사용 가능

describe('Visa', function () {
  let expect = chai.expect;

  it('has a prefix of 4 and a length of 13', function () {
    expect(detectNetwork('4123456789012')).to.equal('Visa');
  });

  it('has a prefix of 4 and a length of 16', function () {
    expect(detectNetwork('4123456789012345')).to.equal('Visa');
  });
});

<React와 TDD>

-> Jest(프레임워크) + Testing Library(라이브러리)

1.Jest & Testing Library

-Jest
테스트 파일을 자동으로 찾아 테스트를 실행, 성공/실패 판단

-Testing Library
BDD/TDD assertion Library for JavaScript Test Framework
Testing Libarary에서 React 용 React Testing Library를 제공
React 프로젝트를 생성하면 자동으로 Testing Library를 이용 가능

참고.assertion
특정 지점에서 개발자가 반드시 참(true)이어야 한다고 생각하는 사항을 표현한 논리식. assertion이 위반되는 경우(즉, 논리식 결과가 거짓)는 프로그램에 버그나 기타 문제가 있는 것을 암시.

2.React 프로젝트 생성 시 내장된 테스트 관련 라이브러리

@testing-library/jest-dom : Jest-dom 제공하는 custom matcher를 사용할 수 있게 해줌
@testing-library/react : 컴포넌트의 요소를 찾기 위한 query가 포함되어 있음
@testing-library/user-event : click 등 사용자 이벤트에 이용

3.사용 예시

// 🗂️App.js
import Light from './components/Light';

function App() {
	return <Light name="전원" />;
}

export default App;
// 🗂️components/Light.jsx
import {useState} from 'react';

function Light({ name }) {
	const [light, setLight] = useState(false);

	return (
		<div>
			<h1>
				{name} {light ? 'ON' : 'OFF'}{' '}
			</h1>
			<button
				onClick={() => setLight(true)}
				disabled={light ? true : false}
			>
				ON
			</button>
			<button
				onClick={() => setLight(false)}
				disabled={!light ? true : false}
			>
				OFF
			</button>
		</div>
	);
}

export default Light;
// 🗂️Light.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Light from './Light';

describe('Light Component tests', () => {
	it('1번', () => {
      	// ① react-testing-library에서 테스트할 컴포넌트를 render() 함수의 인자로 전달
		render(<Light name="전원" />); 
      	// ② getByRole() 메서드를 이용하여 render()에서 가져온 컴포넌트 중 name이 'OFF'인 'button'이 있는지 확인,
      	// 	 offButtonElement 할당
		const offButtonElement = screen.getByRole('button', { name: 'OFF' });
      	// ③ expect 함수의 인자로 지정한 요소가 disabled = false인지 .not.toBeDisabled을 사용하여 체크
		expect(offButtonElement).not.toBeDisabled();
	})

	it('2번', () => {
		render(<Light name="전원" />);
		const onButtonElement = screen.getByRole('button', { name: 'ON' });
      	// fireEvent: 이벤트 생성, 지정된 DOM Node에 해당 이벤트 전달
		fireEvent.click(onButtonElement);
		expect(onButtonElement).toBeDisabled();
	})
})

0개의 댓글