[SWE-012][실무] 테스트로 지키며 오래된 프로그램 고치기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[SWE-012][실무] 테스트로 지키며 오래된 프로그램 고치기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 50회 작성일 26-09-06 18:34

본문

[이번 수업]

기존 가격 계산 코드를 작은 단계로 개선합니다. 현재 동작을 테스트로 고정하고 책임을 나누며 변경 전후 결과와 롤백 기준을 확인합니다.

[선수지식]

SWE-002의 함수·모듈, SWE-003의 단위·통합 테스트, SWE-004의 테스트 우선 개발, SWE-011의 리팩터링과 기술 부채를 알면 좋습니다.

[학습목표]

1. 기존 동작을 특성 테스트로 기록한다.
2. 동작을 유지하며 큰 함수를 작은 책임으로 나눈다.
3. 변경 범위·호환성·배포·롤백을 함께 점검한다.

[핵심개념]

리팩터링은 외부 동작을 유지하며 내부 구조를 개선하는 일입니다. 입력·출력·예외를 관찰해 기준선을 만듭니다. 문서가 부족하면 특성 테스트로 현재 동작을 기록하되 명백한 버그는 기대 동작인지 확인합니다.

회귀는 변경으로 기존 기능이 깨지는 현상입니다. 정상 사례와 경계값·빈 입력·오류를 테스트합니다. 이름 바꾸기, 함수 추출, 중복 제거를 한 종류씩 적용하고 매번 테스트하면 원인 추적과 롤백이 쉽습니다.

개선 전 호출 위치·공개 함수·데이터 형식을 찾습니다. 개선 뒤 정적 검사, 사용자 흐름, 로그도 확인합니다. 공개 계약이 달라지면 호환성과 버전 변경을 기록합니다.

[따라하기]

legacy_price.py를 만드세요. 한 함수가 검증·할인·배송비를 모두 맡는 기존 코드입니다.
```python
def total(items, member=False):
    amount = 0
    for price, quantity in items:
        if price < 0 or quantity < 0:
            raise ValueError("음수는 사용할 수 없습니다")
        amount += price * quantity
    if member:
        amount = int(amount * 0.9)
    if amount < 50000:
        amount += 3000
    return amount
```

test_price.py를 만들어 현재 계약을 고정합니다.
```python
import unittest
from legacy_price import total

class PriceTest(unittest.TestCase):
    def test_shipping_is_added(self):
        self.assertEqual(total([(20000, 2)]), 43000)

    def test_member_discount(self):
        self.assertEqual(total([(30000, 2)], member=True), 54000)

    def test_negative_value_is_rejected(self):
        with self.assertRaises(ValueError):
            total([(-1, 1)])

if __name__ == "__main__":
    unittest.main()
```

먼저 테스트를 실행한 뒤 legacy_price.py를 아래처럼 바꿉니다.
```python
def subtotal(items):
    if any(price < 0 or quantity < 0 for price, quantity in items):
        raise ValueError("음수는 사용할 수 없습니다")
    return sum(price * quantity for price, quantity in items)

def discounted(amount, member):
    return int(amount * 0.9) if member else amount

def shipping(amount):
    return 3000 if amount < 50000 else 0

def total(items, member=False):
    amount = discounted(subtotal(items), member)
    return amount + shipping(amount)
```

macOS·Linux는 `python3 -m unittest -v`, Windows는 `py -m unittest -v`를 실행합니다. 개선 전후 모두 세 테스트와 `OK`가 나와야 합니다. 이는 할인 뒤 금액으로 배송비를 판단하는 기존 동작이 유지됐다는 증거입니다. Git을 사용한다면 테스트 추가와 구조 변경을 별도 커밋으로 남기고 diff에서 의도하지 않은 변경이 없는지 확인하세요.

[흔한 실수]

테스트 없이 정리부터 하거나 구조와 기능 변경을 섞지 마세요. 현재 동작을 무조건 올바르다고 보거나 내부 구현에 묶인 테스트도 피합니다. 배포 전에는 전체 테스트를 실행합니다.

[보안 주의]

운영 데이터·계정·비밀값을 복사하지 말고 가짜 입력과 격리 환경을 사용하세요. 입력 검증·권한·감사 로그는 전후로 테스트합니다. 의존성 출처와 버전을 검토하고 승인된 배포와 롤백을 준비합니다.

[직접 해볼 과제]

빈 장바구니 결과와 정확히 50,000원인 경계값의 기대 결과를 먼저 테스트로 추가하세요. 이어 무료 배송 기준을 인자로 받도록 개선하되 기본 동작은 유지하고, 테스트 추가·코드 변경·전체 재검증을 각각 기록합니다.

[확인문제]

1. 문서가 부족한 기존 코드에서 특성 테스트를 먼저 만드는 이유는 무엇인가요?
2. 구조 개선과 기능 변경을 같은 단계에 섞으면 어떤 문제가 생기나요?
3. 단위 테스트 통과 뒤에도 주요 사용자 흐름과 로그를 확인해야 하는 이유는 무엇인가요?

[다음 학습]

MOBILE-012에서 네트워크가 끊겨도 사용할 수 있는 모바일 앱의 데이터 흐름을 설계합니다.

[공식 참고 자료]

https://docs.python.org/3/library/unittest.html
https://git-scm.com/docs/git-diff
https://semver.org/
https://csrc.nist.gov/pubs/sp/800/218/final

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
540
어제
5,103
최대
16,772
전체
771,594
Copyright © 소유하신 도메인. All rights reserved.