워밍업 클럽 4기 BE - 2주차 발자국

2주차 미션 회고

배운 내용을 토대로 실제 코드에 적용하면서 정말 많은 것을 배우고 느꼈다. 리팩토링에는 정답이 없지만 오답은 있을 수 있다는 것을 깨달았고, 앞으로 개발할 때 클린코드의 진정한 의미에 대해 생각하면서 코드를 작성해야겠다.

 

2주차 강의 회고

클린코드 강의를 마무리하고 본격적인 테스트 코드 강의에 들어가기 전 워밍업 느낌의 1~5장 챕터라고 생각됐다.

테스트의 개념부터 기본적인 테스트 코드 작성법까지 어찌보면 가장 중요한 챕터일지도 모른다는 생각이 들었다.

최대한 꼼꼼히 공부하면서 첫 시작부터 기반을 다진다는 마음가짐으로 강의를 들었다.

 

2주차 학습 내용 요약

테스트가 필요한 이유


  • 테스트 코드를 작성하지 않는다면,

    • 변화가 생기는 매순간마다 발생할 수 있는 모든 케이스를 고려해야 한다.

    • 변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야 한다.

    • 빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.

  • 잘못된 테스트 코드를 작성한다면,

    • 프로덕션 코드의 안정성을 제공하기 힘들어진다.

    • 테스트 코드 자체가 유지보수하기 어려운 짐이 된다.

    • 잘못된 검증이 이루어질 가능성이 생긴다.

  • 올바른 테스트 코드를 작성한다면,

    • 자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있다.

    • 소프트웨어의 빠른 변화를 지원한다.

    • 팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.

    • 가까이 보면 느리지만 멀리 보면 가장 빠르다.

소프트웨어 테스트 종류


기능 테스트

  • 단위 테스트: 하나의 함수나 메서드 단위 동작 검증 (로직 중심)

  • 통합 테스트: 여러 모듈이 함께 동작하는지 확인 (인터페이스, 데이터 흐름 검증)

  • 시스템 테스트: 전체 시스템이 요구사항대로 동작하는지 확인

  • E2E 테스트: 사용자 흐름을 처음부터 끝까지 시뮬레이션하여 기능 동작 여부 확인

  • 회귀 테스트: 기존 기능이 변경 없이 잘 동작하는지 반복 확인

  • 유효성 검사 테스트: 입력값 유효성, 필수 값 누락 등 사용자의 잘못된 입력 처리 검증

  • 조건부 분기 테스트: if/else, switch 등 분기문이 정상적으로 작동하는지 확인

 

비기능 테스트

  • 동시성 테스트: 여러 스레드/사용자가 동시에 접근할 때의 일관성, 충돌 여부 확인

  • 성능 테스트: 시스템이 응답 속도나 처리량 요구사항을 충족하는지 확인

  • 부하 테스트: 많은 사용자나 트래픽이 몰릴 때 성능 저하 없이 동작하는지 확인

  • 스트레스 테스트: 시스템 한계를 넘는 부하에서도 장애 없이 복구 가능한지 확인

단위 테스트 시 검증해야 할 주요 케이스


  • 정상 케이스

    • 기대한 입력값이 주어졌을 때 올바른 결과가 나오는지 확인

    • ex) input = 5output = 25

  • 경계 값 테스트

    • 허용되는 최소/최대값 근처의 입력을 검증

    • ex) min = 1, max = 1000, 1, 100, 101

  • 예외/에러 케이스

    • 잘못된 입력이 들어왔을 때 예외가 잘 처리되는지 확인

    • ex) input = nullIllegalArgumentException 발생

  • 빈 값/Null 처리

    • null, 빈 리스트, 빈 문자열 등 비정상적이지만 흔한 값 검증

    • ex) "", null, [] 입력 처리 확인

  • 중복/경합 조건

    • 동일 입력을 여러 번 넣었을 때 문제가 없는지 확인

    • ex) 중복 ID 처리, 중복 요청 무시 등

  • 상태 기반 테스트

    • 특정 상태 변경 전/후 동작이 예상대로 수행되는지 검증

    • ex) 로그인 전/후 메뉴 접근 가능 여부 등

  • 시간 관련 테스트

    • 시간에 따라 달라지는 로직의 동작 확인

    • ex) 쿠폰 유효 기간, 예약 처리 등

  • 성능 경계 테스트

    • 데이터량이 많을 때 정상 처리 여부

    • ex) 리스트 10,000건 처리 가능 여부 등

테스트하기 어려운 영역


관측할 때마다 다른 값에 의존하는 코드 (현재 날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등)

public class Order {
    public String generateOrderId() {
        return "ORD-" + UUID.randomUUID(); // 매번 다른 값
    }

    public boolean isTodayOrder(LocalDate orderDate) {
        return orderDate.equals(LocalDate.now()); // 현재 날짜 의존
    }
}

외부 세계에 영향을 주는 코드 (표준 출력, 메시지 발송, 데이터베이스 기록 등)

public class Notifier {
    public void sendNotification(String message) {
        System.out.println("Sending message: " + message); // 표준 출력
    }
}

public class UserRepository {
    public void save(User user) {
        // 실제 DB에 저장하는 코드 (예: JDBC, JPA)
        entityManager.persist(user); // 외부 세계에 영속성 부여
    }
}

TDD (Test Driven Development)


테스트를 먼저 작성하고, 그 테스트를 통과하는 최소한의 코드를 구현한 후, 리팩토링하는 개발 방식이다.

// Step 1 (Red): 실패하는 테스트 작성
@Test
void add_shouldReturnSum() {
    Calculator calc = new Calculator();
    assertEquals(5, calc.add(2, 3)); // 아직 add 메서드 없음 → 실패
}

// Step 2 (Green): 테스트 통과하는 최소한의 코드 작성
public int add(int a, int b) {
    return a + b;
}

// Step 3 (Refactor): 코드 리팩토링 (필요시 구조 개선 등)
  • 🔴Red: 실패하는 테스트 작성 (아직 기능이 없으므로 실패)

  • Green: 테스트를 통과할 최소한의 코드 작성

  • 🧹Refactor: 중복 제거 및 코드 정리 (기능은 그대로)

BDD (Behavior Driven Development)


사용자 관점의 시나리오(행동)를 중심으로 기능을 정의하고 테스트하는 접근 방식이다.

Feature: 로그인 기능

  Scenario: 올바른 아이디와 비밀번호 입력 시 로그인 성공
    **Given** 사용자가 로그인 페이지에 접속했을 때
    **When** 아이디와 비밀번호를 올바르게 입력하면
    **Then** 로그인에 성공하고 홈 화면으로 이동한다
  • Given: 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)

  • When: 시나리오 행동 진행

  • Then: 시나리오에 대한 결과 명시, 검증

테스트 제대로 설명하기


- 음료 1개 추가 **테스트** (bad) → ~테스트 문장 지양
- 음료를 1개 **추가할 수 있다.** (not bad) → 명사의 나열보단 문장으로
- 음료를 1개 **추가하면 주문 목록에 담긴다.** (good) → 테스트 행위에 대한 결과까지
- 특정 시간 이전에 주문을 생성하면 **실패한다.** (bad) -> 테스트 현상 중점 기술
- **영업 시간** 이전에는 주문을 생성할 수 없다. (good) -> 도메인 용어 사용
  • ~테스트 문장 지양하기

  • 명사의 나열보단 문장으로 기술하기

  • 테스트 행위에 대한 결과까지 기술하기

  • 도메인 용어를 사용하여 한층 추상화된 내용 담기

  • 테스트의 현상을 중점으로 기술하지 말기

     

댓글을 작성해보세요.

채널톡 아이콘