Test Tip
Last updated
Last updated
vscode >Keyboard Shorcuts > test.run > run test in current file or run test at cursor
ID: vitest.explorer
ID: kingwl.vscode-vitest-runner
ID: ms-playwright.playwright
내부 구현에 대한 테스트 코드는 강한 의존성 때문에 깨지기 쉽고 유지보수 하기 어렵다.
인터페이스를 기준으로 캡슐화에 위반되지 않으며 종속성이 없는 테스트를 작성하자
커버리지를 쫓다보면 큰 유지 보수 비용이 발생하며 제데로 된 검증이 되었다는 착각이 들수 있다.
의미있는 테스트가 무엇인지 고민해보자
테스트 디스크립션을 상세히 명확히 작성하는것이 앱의 동작을 이해하는데 도움된다.
테스트 코드에서도 검증 범위의 책임을 나누는것이 중요하다.
간단한 테스트는 상관없지만, 다양한 컴포넌트들이 조합되었을 때 시나리오를 검증해야 한다면 하나의 테스트에서 한번에 검증하는것이 아닌 여러 개로 나누어 검증하는 것이 가독성과 유지보수성이 높다.
검증에 필요한 코드들이 많아지고 디스크립션도 장황해진다.
여러 개를 검증하다 보니 특정 로직이 수정되어도 테스트 자체가 깨지게 된다.
어떤 동작에서 테스트가 실패했는지 파악하기 어려울 수 있다.
검증의 책임이 명확히 나눠져 있기 때문에 이런 테스트 코드는 유지보수하기 쉽다.
테스트는 독립적인 테스트 케이스가 있고, 테스트 전후에 실행되는 것들(Before**, After**)이 있다.
테스트를 위한 object를 생성하고 여러가지 데이터를 준비하는 과정
준비하는 단계에서는 준비과정을 여러개의 테스트에 걸쳐서 반복해서 사용한다면 재사용할 수 있도록 유틸리티 함수로 정의해서 사용
테스트하고자 하는 코드를 실행
코드를 실행했을 때 의도적으로 실패해보기
expect에 다른값을 넣는다든지, 실패하도록 만든 뒤에 실패했을 때 실패하지 않기 위해서 코드를 어떻게 수정해야하는지 확인해보기
버그를 수정할 때 실패하는 테스트를 먼저 만든 후, 버그가 이런 상황에서 발생하구나를 검증한 다음에 버그를 수정해서 이 테스트 코드가 성공할 수 있도록 만드는것이 중요하다.
실패하지 않는 테스트는 필요 없다.
모든 테스트 코드는 의도적으로 실패할 수 있어야 한다.
실행한 코드를 우리가 예상한값과 같은지 검증
내가 하나의 테스트 함수 안에서 검사하는것이 많다면, 여러개의 테스트로 분리할수 없는지 고민해보자.
Fast: 느린것에 대한 의존성 낮추기,
테스트가 빠르게 수행되어야지 몇개의 테스트를 가지고 있더라도 빈번히 테스트를 수행해서 문제가 없는지 검증하는것이 중요
Isolated: 최소한의 유닛으로 검증하기, 독립적이고 집중적으로 유지
하나의 테스트에서 너무 많은것을 동시에 테스트해서 어디서 어떤것이 잘못되어 테스트가 실패했는지 잘 모르게 작성하지 말고 최소한의 단위로 어디서 실패했는지 한눈에 알 수 있도록 독립적으로 작성
Repeatable: 반복이 가능하도록 만들어라, 테스트코드가 실행될 때마다 동일한 결과 유지
언제, 몇번 실행하냐에 따라서 다른 결과를 제공한다면 나쁜 테스트 코드
다른 테스트 코드에 의존하거나, 외부적 환경(네트워크, 디비)에 의존하는 테스트는 불안정
환경에 영향을 받지 않도록.. 작성
Self-Validating: Assert library(expect, tobe 등)을 사용하면 스스로 결과를 검증 가능
우리가 사용한 테스트 라이브러리는 기본으로 제공
자동화를 통한 검증단계 도입(CI/CD)
새로운 기능을 추가할 때 기존 테스트 코드에 영향을 주는지 확인하지 않으면 테스트 코드는 불필요
Timely: 시기적절하게 테스트 코드 작성
코드를 추가하거나 기능이 수정되고 나서 사용자에게 배포된 후 테스트 코드 작성하는건 의미가 없다.
코드 작성할 때, 리팩토링 전, 사용자에게 배포하기 전에 시기적절하게 테스트 코드 작성해서 예상하지 못한 문제를 빠르게 잡아내는것이 중요
Right-BICEP, 모든 요구사항이 정상 동작하는지 확인
Boundary conditions: 모든 코너케이스에 대해 테스트하기
ex: 잘못된 포맷의 인풋, null, 특수문자, 잘못된 이메일, 작은 숫자, 중복, 순서가 맞지 않는 경우
Inverse relationship: 역관계를 적용해서 결과값을 확인
일관성을 유지 (덧셈 -> 뺼셈, 추가 -> 제거)
Cross-check: 다른 수단을 이용해서 결과값이 맞는지 확인
ex: 추가된 과일 갯수를 구하는 함수를 테스트 한다면, 결과값이 맞는지 확인하기 위해 전체 과일 갯수 - 예전 과일 갯수 값과 동일해야 한다
특정 알고리즘을 구현했다면 정확하게 동작하는지 확인하기 위해서 동일한 알고리즘을 구현한 다른 라이브러리를 이용해서 우리 알고리즘과 라이브러리 알고리즘 결과값이 똑같아야 한다.
Error conditions: 불행한 경로에 대해 우아하게 처리 하는가?
네트워크 에러, 메모리 부족, 데이터베이스 중지 등
예상할 수 있는 모든 에러 케이스에 대해서 테스트가 통과하는지
Performance chracteristic: 성능 확인은 테스트를 통해 정확한 수치로 확인
성능 개선의 척도와 확인도 데이터를 통해 확인
테스트도 각각 상황 및 조건에 맞게 어떤 결과값을 예상하는지를 테스트하는것이 중요 -> CORRECT 원칙
단순히 하나의 사실에 의거해서 테스트를 작성하는게 아닌, 여러가지 조건들을 테스트해서 테스트 코드도 꼼꼼히 작성
CORRECT
원칙은 테스트 코드 뿐만 아니라 베이스 코드를 작성할 때도 유념
Conformance: 특정 포맷을 준수
전화번호, 이메일, 아이디, 파일 확장자 등
인풋이 포맷에 적합할 때, 적합하지 않을 때, 우리 코드가 어떤식으로 동작하는지 예상하는 테스트 코드를 작성
Ordering: 순서 조건 확인하기
순서가 중요한 경우
테스트 코드가 배열의 순서를 중요하게 생각하는 코드라면, 순서가 잘못되었을 때 코드가 어떻게 반응할것인지 예상하는것들도 모두 테스트로 나타내야함
Range: 숫자의 범위
제한된 범위보다 크거나 작은 경우
Reference: 외부 의존성 유무, 특정한 조건의 유무
~일때, ~가 되었을 때, 어떤 특정한 상황/상태 일경우 이런 동작을 한다.
Existence: 값이 존재하지 않을 때 어떻게 동작?
null, undefined, 0, ''
Cardinality: 0-1-N 법칙에 따라 검증
하나도 없을 때, 하나만 있을 때, 여러개 있을 때
Time: 상대, 절대, 동시에 일들
순서가 맞지 않은 경우, 소비한 시간, 지역 시간
순서가 맞지 않을 때, 특정 시간을 지나치게 소비했을 때, 시간을 검사한다면 지역마다 나라마다 시간이 달라지는 경우 코드가 어떻게 동작하는지 검사
여러가지 조건에 맞게 테스트를 작성하다 보면 베이스 코드에 놓친 부분을 파악하는 상황이 자주 생김!
itteration speed vs Realistic envirionment
itteration speed: 특정한 일을 시작해서 끝날때까지 걸리는 속도
즉, 기능 구현후 테스트 코드 작성하고 검증하는 단계를 한바퀴 돌아오는 속도
코드 수정 후 기존 테스트를 동작해서 결과 확인해서 완성하는 한바퀴를 iteration
이라 한다.
테스트 작성하고 테스트 동작하는 속도가 빠르면 빠를 수록 iteration speed는 빠르다고 볼 수 있다.
Realistic envirionment: 사용자가 실제로 앱을 사용했을 때의 환경과 최대한 가까운것
테스트에서 제일 필수적인 조건으로 "동일한 인풋이 주어졌을 때 동일한 결과를 도출해야한다" 인데 환경에 따라 결과가 달라지면 최악의 테스트...그래서 E2E 테스트는 실제 브라우저 환경에서 동작하도록 해서 좋은 테스트이지만 itteration speed
가 떨어지고 간혹 테스트가 실패하는 문제점이 있다.
How much to Mock
얼마만큼 Mock을 할것인가
컴포넌트를 테스트하는 경우 유닛인지 통합인지 경계가 불명확하다.
어디까지 유닛테스트로 부르고, 어디까지 통합 테스트로 부를것인지는 사실 중요하지 않다.
util, api, 단일 컴포넌트는 유닛 테스트, 다른 컴포넌트 또는 외부 리소스를 사용한다면 통합 테스트 ㅇㅇ
조금 더 테스트를 간편하게 만들어주고, 테스트 자체만으로 유지보수성을 높혀줌
리액트 컴포넌트를 내부 구현사항에 의존하지 않고 테스트를 간편하게 만들어줌
리엑트 컴포넌트를 테스트할 때 내부적으로 어떤 CSS를 사용하는지, 어떤 코드를 가지고 있는지 구현사항에 의존하지 않고 화면상에, 사용자 입장에서 '특정 텍스트를 갖는 버튼을 가져와서 클릭하거나, 텍스트가 보이는지 안보이는지' 조금 더 외부적인 사용자 관점에서 테스트를 작성할 수 있도록 도와줌
이런 접근법은 리팩토링을 쉽게 만들어주고, 웹 접근성과 코드를 작성하는데 좋은 원칙을 따라갈 수 있게 도와줌
검증하려는 기능과 관계없는 코드가 수정되도 테스트가 실패하는 상황을 만들지 말자
단점으로 RTL 자체로는 자식 노드들을 가볍게 렌더링하는건 제공하지 않음
컴포넌트 하나만 테스트하더라도 내부 컴포넌트들을 모두 렌더링하게됨
내부 컴포넌트들이 갖는 의존성까지 모두 설정해줘야해서 까다로움
jest/vitest 의 mock 활용