왜 테스트를 작성하는가
테스트 자동화
- 장점
- 사람이 수행해야 하는 반복된 테스트를 자동화 할 수 있음 (비용 감소)
- 사람이 수행하는 것보다 훨씬 빠르게 테스트할 수 있음
- 사람이 수행하는 것보다 더 신뢰할 수 있음
- 단점
- 감각적인 요소(시각, 청각) 등 사용자 경험과 관련된 문제를 찾아낼 수 없음
- 실제 환경에서 벌어지는 다양한 상황을 자동화하기 어려움 (네트워크, 디바이스 관련 등)
개발자가 테스트 작성해야 하는 이유
- 제품 품질
- 개발자는 작성한 프로그램의 퀄리티에 대한 책임이 있음
- QA에 넘기기 전에 기본 요구사항을 모두 만족하는지에 대한 검증은 개발자가 해야 함
- 자동화된 테스트를 작성해 두지 않으면, 어플리케이션이 복잡해질 수록 테스트 비용이 증가함
- 이 경우 개발 기간이나 인력 등은 한정되어 있기 때문에, 테스트를 소홀히 하게 되는 경우가 많음.
- 그렇지 않은 경우 QA 와의 커뮤니케이션 비용이 늘어나, 업무 효율이 떨어지게 됨
- 코드 품질
- 코드 품질을 위해서는 계속해서 리팩토링 등의 개선 작업이 필요
- 이 과정에서 기존에 잘 동작하던 프로그램을 망칠 수 있기 때문에 적극적으로 코드를 개선하지 않게 됨
- 신뢰할 수 있는 자동화된 테스트가 있으면 적극적으로 코드를 개선할 수 있음
테스트 코드가 없을 때 -> 테스트 코드가 있을 때
두려움(Fear) -> 자신감(Confidence)
테스트의 종류
- 단위(Unit) 테스트
- 통합(Integation) 테스트
- E2E(End to End) 테스트
- 기능(Functional) 테스트
- 시스템(System) 테스트
- UI(User Interface) 테스트
- 회귀(Regression) 테스트
- 성능(Performance) 테스트
1. 단위(Unit) 테스트
- 모듈(함수/클래스) 단위의 테스트
- 테스트할 부분의 코드를 다른 시스템으로부터 분리시킨 채 테스트
- 작성 비용이 적게 들고 실행 속도가 빠름
- 실패했을 때 문제가 생긴 부분을 비교적 정확하게 파악할 수 있음
- 경우에 따라 한두개의 단위를 모아서 하나의 단위로 취급하기도 함
- Sociable (같이) vs Solitary (혼자)
- Sociable Tests : 의존성이 있는 다른 코드들과 함께 테스트
- Solitary Tests : 테스트 더블을 이용해 완벽하게 분리시킨 채 테스트
- 경우에 따라 적절한 방법을 사용
2. E2E(End to End) 테스트
- 실제 사용자가 사용하는 것과 같은 조건에서 전체 시스템을 테스트
- API 서버, DB 등의 외부 서비스들을 모두 사용하여 통합된 시스템을 테스트
- 단위/통합 테스트에 비해 작성이 어렵고 실행 속도가 가장 느림
- 문제가 생긴 부분을 정확히 파악하기가 가장 어려움
- 기능(Functional) 테스트와 비슷한 의미로 사용됨
좋은 테스트에 대한 고민
🤔 좋은 테스트란?
1. 실행 속도가 빨라야 한다.
- 빠른 피드백은 개발 속도를 향상시켜준다.
- 너무 느리면 테스트를 자주 실행하지 않게 된다.
2. 내부 구현 변경 시 실패하지 않아야 한다.
- 리팩토링할 때 테스트가 깨진다면? -> 오히려 코드 개선을 방해
- 자주 변하는 로직과 변하지 않는 로직을 구분
3. 버그를 검출할 수 있어야 한다.
- 소스 코드에 버그가 있어도 검출하지 못한다면 잘못된 테스트
- 테스트가 기대하는 결과를 구체적으로 명시하지 않으면 버그를 검출할 수 없음
4. 테스트의 결과가 안정적이어야 한다.
- 특정 환경에서만 실패하거나, 실행할때마다 결과가 달라지는 테스트는 신뢰할 수가 없음
- 외부 환경의 영향을 최소화해서 동일한 결과를 최대한 보장할 수 있는게 중요함
5. 의도가 명확히 드러나야 한다.
- 가독성 : "기계가 읽기 좋은 코드" ⇒ "사람이 읽기 좋은 코드"
- 테스트 코드를 보고 한 눈에 어떤 내용을 테스트하는지를 파악할 수 있어야 함
✔️ Kent Beck - Test Desderata 12계론
1. Isolated (분리)
- tests should return the same results regardless of the order in which they are run.
- 테스트는 실행 순서에 관계없이 동일한 결과를 반환해야 합니다.
2. Composable (구성가능)
- if tests are isolated, then I can run 1 or 10 or 100 or 1,000,000 and get the same results.
- 테스트가 격리된 경우 1, 10, 100 또는 1,000,000을 실행해도 동일한 결과를 얻을 수 있습니다.
3. Fast (빠른)
- tests should run quickly.
4. Inspiring (영감을 주는, 격려하는)
- passing the tests should inspire confidence
5. Writable (쓰기 가능)
- tests should be cheap to write relative to the cost of the code being tested.
- 테스트는 테스트 중인 코드 비용에 비해 작성 비용이 적어야 합니다.
6. Readable (읽기 가능)
- tests should be comprehensible for reader, invoking the motivation for writing this particular test.
- 테스트는 독자가 이해할 수 있어야 하며, 이 특정 테스트를 작성하는 동기를 불러일으킵니다.
7. Behavioral (행동)
- tests should be sensitive to changes in the behavior of the code under test.
If the behavior changes, the test result should change.
- 테스트는 테스트 중인 코드의 동작 변화에 민감해야 합니다.
동작이 변경되면 테스트 결과도 변경되어야 합니다.
8. Structure-insensitive (구조에 민감하지 않음)
- tests should not change their result if the structure of the code changes.
- 코드 구조가 변경되더라도 테스트 결과가 변경되어서는 안 됩니다.
9. Automated (자동화)
- tests should run without human intervention.
- 테스트는 사람의 개입 없이 실행되어야 합니다.
10. Specific (구체적인)
- if a test fails, the cause of the failure should be obvious.
- 테스트가 실패하면 실패 원인이 분명해야 합니다.
11. Deterministic (결정적)
- if nothing changes, the test result shouldn’t change.
- 아무것도 변경되지 않으면 테스트 결과가 변경되지 않아야 합니다.
12. Predictive (예측)
- if the tests all pass, then the code under test should be suitable for production.
- 테스트가 모두 통과되면 테스트 중인 코드가 프로덕션에 적합해야 합니다.
인프런 - 하루만에 Cypress로 작성하는 자바스크립트 E2E 테스트 코드