개념
이름은 달라도 뼈대는 같다
Java는 JUnit, Python은 pytest, JavaScript는 Jest(또는 Vitest)를 주로 쓴다. 언어마다 도구 이름이 다르니 완전히 별개로 보이지만, 이들은 모두 1998년에 만들어진 원조 프레임워크 SUnit/JUnit의 구조를 계승한다 — 그래서 통칭 **"xUnit 계열"**이라 부른다. 하나의 구조를 이해하면 나머지도 낯설지 않다.
공통 구조 1 — 테스트 러너(Test Runner)
테스트 파일들을 찾아서 실행하고, 결과(통과/실패/에러)를 모아 보고서로 보여주는 도구다. 보통 명령어 한 줄로 프로젝트 전체의 테스트를 돈다.
# 언어마다 명령어는 다르지만 하는 일은 같다
pytest # Python
npx jest # JavaScript
./gradlew test # Java (JUnit)공통 구조 2 — 어서션(Assertion)
레슨 1의 AAA 패턴에서 "Assert" 단계에 쓰이는 문법이다. "이 값이 저 값과 같아야 한다", "이 값이 참이어야 한다" 같은 검증 문장을 표현한다.
// Jest
expect(result).toBe(9000)
expect(isValid).toBeTruthy()# pytest
assert result == 9000
assert is_valid// JUnit
assertEquals(9000, result);
assertTrue(isValid);표현 방식은 다르지만 전부 "기대값과 실제값을 비교해서, 다르면 테스트를 실패시킨다"는 같은 일을 한다.
공통 구조 3 — Setup과 Teardown
여러 테스트가 공통으로 필요한 준비 작업(레슨 1의 Arrange에 해당)을 매번 반복해서 쓰지 않도록, 테스트 실행 전후에 자동으로 실행되는 훅이 있다.
beforeEach(() => {
// 각 테스트 실행 전에 매번 실행 — 예: 테스트용 장바구니 초기화
})
afterEach(() => {
// 각 테스트 실행 후에 매번 실행 — 예: 테스트 데이터 정리(모듈 7 레슨 2의 리셋과 연결)
})이 개념은 모듈 7(레슨 2)에서 배운 시딩과 리셋이 테스트 코드
수준에서 구현된 형태다 — beforeEach가 시딩, afterEach가 리셋
역할을 한다.
테스트 결과 읽는 법
테스트를 실행하면 보통 이런 형태의 결과가 나온다.
✓ 10% 할인율이면 가격이 10% 줄어든다 (2ms)
✗ 재고가 0이면 구매 버튼이 비활성화된다 (1ms)
Expected: true
Received: false
Tests: 1 failed, 1 passed, 2 total실패한 테스트는 기대값(Expected)과 실제값(Received)을 나란히 보여준다 — 이 두 값의 차이가 바로 "무엇이 예상과 다르게 동작했는가"에 대한 직접적인 단서다.
실무에서 왜 필요한가
CI 파이프라인(스테이지 4에서 다룬다)이 실패했을 때, 그 로그에 찍힌 Expected/Received 값을 읽을 줄 알면, 개발자를 부르기 전에 QA 스스로 "이게 실제 버그인지, 테스트 코드 자체의 문제인지" 1차 판단을 할 수 있다. 또한 여러 언어를 넘나드는 프로젝트(백엔드는 Python, 프론트엔드는 JavaScript)에서도, 프레임워크 이름에 겁먹지 않고 "이것도 결국 AAA 구조겠지"라고 접근할 수 있다.
실습 과제
과제 1 — 프레임워크 간 대응 관계 찾기 (10분)
다음 Jest 코드와 같은 의미의 pytest 코드를 이 레슨에서 배운 어서션 문법을 참고해 작성해본다.
test("빈 장바구니는 총액이 0이다", () => {
expect(calculateTotal([])).toBe(0)
})과제 2 — 실패 결과 해석하기 (10분)
다음 테스트 결과를 보고, 어떤 값이 예상과 다르게 나왔는지, 그리고 이게 코드 버그인지 테스트 코드 문제인지 확인하려면 무엇을 먼저 봐야 할지 적는다.
✗ VIP 회원은 배송비가 무료다 (3ms)
Expected: 0
Received: 3000자가 체크리스트
- xUnit 계열 프레임워크들이 공유하는 공통 구조 세 가지(러너·어서션·setup/teardown)를 설명할 수 있다
- 서로 다른 언어의 어서션 문법이 결국 같은 개념이라는 것을 이해한다
- beforeEach/afterEach가 모듈 7(레슨 2)의 시딩·리셋과 어떻게 연결되는지 설명할 수 있다
- 테스트 실패 결과에서 Expected/Received 값을 읽고 원인을 추정할 수 있다
흔한 실수
- 프레임워크 이름이 낯설면 아예 읽기를 포기한다. 이름은 달라도 구조는 거의 항상 같다.
- Expected/Received 값을 확인하지 않고 "테스트가 실패했다"는 사실만 보고 원인을 개발자에게 전부 떠넘긴다. 두 값을 비교하는 것만으로도 1차 원인 추정이 가능한 경우가 많다.
- setup/teardown 없이 매 테스트가 서로 영향을 주는 코드를 정상으로 여긴다. 이는 모듈 7(레슨 3)에서 배운 플래키 테스트의 흔한 원인이다.
참고 자료
- Jest 공식 문서 — JavaScript 테스트 프레임워크의 공식 가이드
- pytest 공식 문서 — Python 테스트 프레임워크의 공식 가이드
- JUnit 5 사용자 가이드 — Java 테스트 프레임워크의 공식 가이드