코드 작성 만큼 중요한 것은 무엇일까 ?
- 좋은 코드를 작성할 수 있는 환경을 구축하는 것
- 좋은 코드를 작성하기 위한 사전 작업 ⇒ ESLint, 테스트 라이브러리
8.1 ESLint를 활용한 정적 코드 분석
정적 코드 분석?
코드 자체만으로 잠재적 버그를 야기할 수 있는 문제를 찾아 사전에 수정하는 것을 의미
가장 많이 사용되는 정적 코드 분석 도구 ⇒ ESLint
ESLint는 어떻게 코드를 분석할까?
!https://tech.kakao.com/storage/2019-11-25__8.13.19-1024x300.png
- 자바스크립트 코드를 문자열로 읽음
- 자바스크립트 코드를 분석 할 수 있는 파서(parser)로 코드를 구조화
- ESLint에서 파서는 기본적으로 espree 사용
- 2번에서 구조화한 트리를 AST(Abstract Syntax Tree)라 하며, 이 구조화된 트리를 기준으로 각종 규칙과 대조함
- 규칙과 대조 시 위반한 코드를 알리거나(report) 수정(fix)
ESLint 코드 분석 예시
function hello(str) {}
{
"type": "Program",
"start": 0,
"end": 22,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 22,
"id": {
"type": "Identifier",
"start": 9,
"end": 14,
"name": "hello"
},
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 15,
"end": 18,
"name": "str"
}
],
"body": {
"type": "BlockStatement",
"start": 20,
"end": 22,
"body": []
}
}
],
"sourceType": "module"
}
변수인지, 함수인지, 함수명이 무엇인지 뿐만 아닌 코드의 정확한 위치와 같은 세세한 정보도 담겨있다.
espree로 코드를 분석한 결과를 바탕으로 어떤 코드가 잘못된 코드이며 어떻게 수정해야 할지 정하는 것을 **ESLint 규칙(rules)**라고 한다. 또한, 특정 규칙의 모음을 plugins 라고 칭한다.
debugger 사용 금지 예시
{
"type": "Program",
"start": 0,
"end": 9,
"body": [
{
"type": "DebuggerStatement",
"start": 0,
"end": 9
}
],
"sourceType": "module"
}
type이 DebuggerStatement임을 확인할 수 있음.
module.export = {
meta: {
type: 'problem',
docs: {
description: 'Disallow the use of `debugger`,
recommended: true,
url: '<https://eslint.org/docs/rules/no-debugger>',
},
fixable: null,
schema: [],
messages: {
unexpected: 'Unexpected 'debugger' statement.",
}
},
},
// 실제로 코드에서 문제점을 확인하는 곳
create(context) {
DebuggerStatement(node) {
context.report({
node,
messageId: 'unexpected',
})
},
}
},
}
- create 함수는 espree로 만들어진 AST 트리를 실제로 순회 한다.
- 위 코드에서 선언한 특정 조건을 만족하는 코드를 찾고, 이 작업을 코드 전체에서 반복한다.
- DebuggerStatement를 만나면 해당 노드를 리포트해 debugger를 사용했다는걸 알려준다.
ESLint를 설치하고 사용하려면 어떤것들을 준비해야 할까?
- eslint-plugin
- eslint-config
eslint-plugin
- eslint-plugin 이라는 접두사로 시작하는 플러그인은 앞서 언급했던 규칙을 모아놓은 패키지
- ex) eslint-plugin-import, eslint-plugin-react …
eslint-config
- eslint-plugin이 특정 프레임워크나 도메인 관련 규칙 프레임워크라면, eslint-config는 이러한 eslint-plugin을 한데 묶어서 완벽하게 한 세트로 제공하는 패키지
- 보통 개인이 직접 만드는 경우는 드물고 IT 기업들에서 공개한 잘 만들어진 eslint-config를 설치해서 사용
- eslint-config-airbnb
- 리액트 기반 프로젝트에서 쓰기 좋음
- @titicaca/triple-config-kit
- 자체적으로 정의한 규칙을 기반으로 운영됨
- 외부로 제공하는 규칙에 대한 테스트 코드가 존재
- CI/CD 환경, 카나리 배포 등 일반적인 npm 라이브러리 구축 및 관리를 위한 시스템이 잘 구축되어 있음
- eslint-config-next
- Next.js 프레임워크 사용 환경에서 사용 할 수 있음
- 단순 JS 코드 정적분석 뿐만 아닌 JSX 구문 및 HTML 코드 또한 정적 분석 대상으로 분류해 제공
- 웹 서비스 성능에 영향을 미치는 요소를 분석해 제공하는 기능도 포함
- eslint-config-airbnb
ESLint 사용 시 주의할 점
- Prettier와의 충돌
- ESLint는 자바스크립트에서만 작동하지만 Prettier는 다양한 언어에도 적용 가능
- ESLint에서도 Prettier에서 처리하는 작업(들여쓰기, 줄바꿈, 따옴표, 최대 글자 수) 등 처리 할 수 있기 때문에 두 가지 모두 자바스크립트 코드에서 실행하면 서로 충돌하는 규칙으로 에러 발생
- 서로 규칙이 충돌되지 않게 Prettier에서 제공하는 규칙은 ESLint에서 끄자.
- 자바스크립트나 타입스크립트는 ESLint에 맡기고, 그 외 파일은 Prettier에 맡겨 물리적으로 분리하자.
- 규칙에 대한 예외 처리
- eslint-disable- 주석 사용 시 특정 규칙을 임시로 무시 할 수 있음.
- ex) 의존 배열이 필요한 훅에 의존성 배열을 제대로 선언했는지 확인하는 역할 비활성화 eslint-disable-line no-exhaustive-deps
- eslint-disable를 많이 사용하고 있다면 이렇게 규칙을 무시하는 것이 옳은지, 규칙을 아예 제거하는게 옳은지 점검이 필요함.
- eslint-disable- 주석 사용 시 특정 규칙을 임시로 무시 할 수 있음.
- ESLint 버전 충돌
- 두 개의 다른 ESLint 버전이 설치되어 에러가 발생
- ESLint를 peerDependencies로 설정해두길 권장
8.2 리액트 팀이 권장하는 리액트 테스트 라이브러리
테스트
- 개발자가 만든 프로그램이 코딩을 한 의도대로 작동하는지 확인하는 일련의 작업
DOM Testing Library
- jsdom을 기반으로 테스트를 수행하는 라이브러리
- jsdom? 순수하게 자바스크립트로 작성된 라이브러리로 Node.js 같은 환경에서도 HTML과 DOM을 사용할 수 있도록 해주는 라이브러리
React Testing Library
- DOM Testing Library를 기반으로 만들어졌음. 리액트 기반 환경에서 리액트 컴포넌트를 테스트 할 수 있는 라이브러리
- 해당 라이브러리를 사용하면 실제로 리액트 컴포넌트를 렌더링 하지 않고도 원하는 대로 렌더링 되는지 확인 가능
테스트 코드를 작성하는 과정
- 테스트 할 함수나 모듈 선정
- 함수나 모듈이 반환하길 기대하는 값 작성
- 함수나 모듈의 실제 반환 값 작성
- 3번 과정의 기대에 따라 2번의 결과가 일치하는지 확인
- 기대하는 결과 반환 시 테스트 성공, 다른 결과 반환시 에러 던짐
위 과정을 위해 가장 먼저 필요한 것?
“ 작성한 코드가 예상대로 동작 하면 성공 메시지 출력, 실패하면 에러 던지기 “
Node.js의 assert라는 모듈을 사용하면 위처럼 작동 가능!
const assert = require('assert')
function sum(a, b) {
return a + b
}
assert.equal(sum(1,2), 3) // 성공
assert.equal(sum(1,2), 4) // Assertion Error [ERR_ASSERTION] [ERR_ASSERTION]: 3 == 4
위처럼 테스트 결과를 확인할 수 있도록 도와주는 라이브러리를 어설션(assetion)라이브러리라고 한다.
단순히 동등을 비교하는 equal 외에도 객체 자체가 동일한지 확인하는 deepEqual, 같지 않은지 비교하는 notEqual, 에러 던지는 여부를 확인하는 throws 등 다양한 메서드를 제공한다.
좋은 테스트 코드
- 어떤 테스트가 무엇을 테스트 하는지 일목 요연하게 기승전결을 보여주는 것 ⇒ 테스팅 프레임워크 사용
- 자바스크립트의 유명 테스트 프레임워크
- Jest, Mocha, karma, Jasmine 등
리액트 컴포넌트 테스트 코드 작성하기
- 컴포넌트를 렌더링한다.
- 필요하면 컴포넌트에서 특정 액션을 수행한다.
- 컴포넌트 렌더링과 2번의 액션을 통해 기대하는 결과와 실제 결과를 비교한다.
리액트 컴포넌트에서의 테스트 코드 종류
- 정적 컴포넌트
- 별도의 상태가 존재하지 않아 항상 같은 결과를 반환하는 컴포넌트
- 테스트를 원하는 컴포넌트를 렌더링 후 테스트 원하는 요소를 찾아 테스트를 수행하면 된다.
- 동적 컴포넌트
- 사용자 액션이 있는 동적 컴포넌트
- jest에서 사용자 작동을 흉내내는 메서드들을 사용해서 테스트한다.
- 비동기 이벤트가 발생하는 컴포넌트
- Node.js나 브라우저에서 모두 사용할 수 있는 모킹 라이브러리 MSW(Mock Service Worker) 사용
- 네트워크 요청을 수행하고 이 요청을 중간에 MSW가 감지하고 미리 준비한 모킹 데이터를 제공하는 방식으로 테스트한다.
- 사용자 정의 훅
- 훅 테스트를 편리하게 할 수 있도록 도와주는 react-hooks-testing-library 사용
테스트 작성하기에 앞서 고려할 점
- 프론트엔드 코드는 사용자의 입력이 매우 자유로워 모든 상황을 커버하는 테스트 코드를 작성하기 불가능
- 테스트 코드를 작성하기 전에 애플리케이션에서 가장 취약하거나 중요한 부분 파악이 우선
- 테스트가 모두 통과 했다는 것을 보는 것이 아닌 소프트웨어 품질에 대한 확신을 얻기 위해 테스트 코드를 작성하는 것임을 명심하기!
그 밖에 여러가지 테스트들
- 유닛 테스트
- 각각의 코드나 컴포넌트가 독립적으로 분리된 환경에서 의도된 대로 작동하는지 검증하는 테스트
- 통합 테스트
- 유닛 테스트를 통과한 여러 컴포넌트가 묶여서 하나의 기능으로 작동하는지 확인하는 테스트
- 엔드 투 엔드 테스트
- 실제 사용자처럼 작동하는 로봇을 활용해 애플리케이션의 전체적인 기능을 확인하는 테스트
'Study' 카테고리의 다른 글
| [모던 리액트 Deep Dive 스터디] 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표 (0) | 2024.04.21 |
|---|---|
| [모던 리액트 Deep Dive 스터디] 리액트 17과 18의 변경사항 살펴보기 (1) | 2024.04.13 |
| [모던 리액트 Deep Dive 스터디] 모던 리액트 개발 도구로 개발 및 배포환경 구축하기 (0) | 2024.04.07 |
| [모던 리액트 Deep Dive 스터디] 크롬 개발자 도구를 활용한 애플리케이션 분석 (1) | 2024.03.23 |
| [모던 리액트 Deep Dive 스터디] 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (0) | 2024.03.10 |