본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 25. · 4 Views
테스트 자동 생성 워크플로 완벽 가이드
LLM을 활용하여 코드로부터 자동으로 테스트 케이스를 생성하고, Edge Case를 발견하며, TDD 워크플로를 자동화하는 실무 가이드입니다. pytest와 jest를 활용한 실습 예제를 포함합니다.
목차
- 코드로부터_테스트_케이스_자동_생성
- Unit과_Integration_테스트_자동_작성
- Edge_Case_자동_발견
- 테스트_실행과_피드백_루프
- 실습_pytest_테스트_생성기_만들기
- 실습_TDD_워크플로_자동화
1. 코드로부터 테스트 케이스 자동 생성
어느 날 김개발 씨는 급하게 신규 기능을 개발하느라 테스트 코드를 작성하지 못했습니다. 코드 리뷰 시간이 다가오자 불안한 마음이 들었습니다.
선배 박시니어 씨가 다가와 말했습니다. "테스트 코드 작성, LLM한테 시켜보는 건 어때요?"
테스트 자동 생성은 작성된 코드를 분석하여 자동으로 테스트 케이스를 만들어내는 기법입니다. LLM은 코드의 의도를 이해하고, 예상되는 입출력 시나리오를 파악하여 테스트 코드를 생성합니다.
개발자는 생성된 테스트를 검토하고 필요한 부분만 수정하면 됩니다.
다음 코드를 살펴봅시다.
# 원본 함수: 사용자 등급 계산
def calculate_user_grade(purchase_amount, years_subscribed):
# VIP: 100만원 이상 구매 또는 5년 이상 구독
if purchase_amount >= 1000000 or years_subscribed >= 5:
return "VIP"
# GOLD: 50만원 이상 구매 또는 3년 이상 구독
elif purchase_amount >= 500000 or years_subscribed >= 3:
return "GOLD"
# SILVER: 10만원 이상 구매
elif purchase_amount >= 100000:
return "SILVER"
# 기본 등급
return "BRONZE"
김개발 씨는 입사 6개월 차 주니어 개발자입니다. 이번 스프린트에서 사용자 등급 계산 로직을 개발했는데, 테스트 코드를 작성할 시간이 부족했습니다.
코드 리뷰 미팅이 내일인데, 테스트 없이 배포할 수는 없는 노릇입니다. 고민하던 김개발 씨에게 선배 박시니어 씨가 조언을 건넸습니다.
"요즘은 LLM한테 테스트 생성을 맡기는 팀도 많아요. 한번 시도해보는 건 어때요?" 그렇다면 LLM 기반 테스트 자동 생성이란 정확히 무엇일까요?
쉽게 비유하자면, 테스트 자동 생성은 마치 요리사가 레시피를 보고 맛을 검증하는 체크리스트를 만드는 것과 같습니다. 레시피(코드)를 읽고 "단맛은 충분한가?", "염도는 적절한가?"와 같은 검증 항목(테스트 케이스)을 자동으로 작성하는 것입니다.
이처럼 LLM도 코드를 읽고 검증이 필요한 시나리오를 파악합니다. 테스트 자동 생성이 없던 시절에는 어땠을까요?
개발자들은 모든 테스트 케이스를 직접 생각하고 작성해야 했습니다. 함수 하나당 최소 5-10개의 테스트 케이스를 작성하려면 상당한 시간이 소요됩니다.
더 큰 문제는 놓치는 케이스가 생긴다는 것이었습니다. 개발자가 생각하지 못한 경계값이나 예외 상황은 테스트되지 않고 넘어가기 일쑤였습니다.
바로 이런 문제를 해결하기 위해 LLM 기반 테스트 자동 생성이 등장했습니다. LLM을 사용하면 코드를 입력하는 것만으로 다양한 테스트 케이스를 자동 생성할 수 있습니다.
또한 개발자가 미처 생각하지 못한 엣지 케이스도 발견해줍니다. 무엇보다 테스트 작성 시간을 대폭 단축할 수 있다는 큰 이점이 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 2번째 줄에서 구매 금액과 구독 연수를 매개변수로 받습니다.
이 두 값의 조합에 따라 등급이 결정됩니다. 4-5번째 줄은 VIP 등급 조건을 확인합니다.
100만원 이상이거나 5년 이상이면 VIP가 됩니다. 7-8번째 줄은 GOLD 등급, 10-11번째 줄은 SILVER 등급을 판정합니다.
마지막으로 어느 조건도 만족하지 않으면 BRONZE가 반환됩니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 전자상거래 플랫폼을 개발한다고 가정해봅시다. 결제 로직, 할인 계산, 재고 관리 등 다양한 비즈니스 로직이 존재합니다.
이러한 함수들에 대해 LLM이 자동으로 테스트를 생성해주면, 개발자는 비즈니스 로직 구현에만 집중할 수 있습니다. 넷플릭스, 구글과 같은 많은 기업에서 이런 패턴을 적극적으로 도입하고 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 LLM이 생성한 테스트를 검토 없이 그대로 사용하는 것입니다.
LLM은 완벽하지 않으며, 때로는 불필요한 테스트나 잘못된 예상 결과를 생성할 수 있습니다. 따라서 반드시 생성된 테스트를 리뷰하고 비즈니스 로직에 맞게 수정해야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 조언을 따라 LLM에게 테스트 생성을 요청한 김개발 씨는 놀랐습니다.
몇 초 만에 10개가 넘는 테스트 케이스가 생성되었고, 자신이 미처 생각하지 못한 경계값 테스트도 포함되어 있었습니다. 테스트 자동 생성을 제대로 이해하면 개발 속도를 높이면서도 코드 품질을 유지할 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - LLM에게 코드와 함께 비즈니스 요구사항을 설명하면 더 정확한 테스트가 생성됩니다.
- 생성된 테스트 중 중복되거나 불필요한 것은 과감히 제거하세요.
- 테스트 커버리지 도구를 함께 사용하여 누락된 분기를 확인하세요.
2. Unit과 Integration 테스트 자동 작성
김개발 씨는 테스트가 두 종류로 나뉜다는 것을 알게 되었습니다. 유닛 테스트와 통합 테스트.
선배 박시니어 씨가 설명합니다. "이 둘은 목적이 다르죠.
LLM은 둘 다 자동으로 만들 수 있어요."
유닛 테스트는 개별 함수나 클래스를 독립적으로 테스트하며, 통합 테스트는 여러 컴포넌트가 함께 동작하는 것을 검증합니다. LLM은 코드의 의존성 구조를 분석하여 적절한 수준의 테스트를 생성합니다.
목(Mock) 객체가 필요한 경우 자동으로 추가해줍니다.
다음 코드를 살펴봅시다.
# LLM이 생성한 유닛 테스트
import pytest
from user_service import calculate_user_grade
def test_vip_grade_by_purchase():
# VIP 등급: 구매 금액 기준
assert calculate_user_grade(1000000, 0) == "VIP"
assert calculate_user_grade(1500000, 2) == "VIP"
def test_vip_grade_by_subscription():
# VIP 등급: 구독 연수 기준
assert calculate_user_grade(0, 5) == "VIP"
assert calculate_user_grade(300000, 6) == "VIP"
def test_boundary_values():
# 경계값 테스트
assert calculate_user_grade(999999, 4) == "GOLD"
assert calculate_user_grade(99999, 2) == "BRONZE"
김개발 씨는 처음 생성된 테스트 코드를 보고 의문이 들었습니다. "이 테스트들은 함수 하나만 검증하는데, 실제로는 데이터베이스나 다른 서비스와 연동되잖아요.
그런 건 어떻게 테스트하죠?" 박시니어 씨가 웃으며 대답했습니다. "좋은 질문이에요.
그게 바로 유닛 테스트와 통합 테스트의 차이입니다." 유닛 테스트와 통합 테스트의 차이는 무엇일까요? 쉽게 비유하자면, 유닛 테스트는 자동차의 엔진만 따로 떼어내서 작동하는지 확인하는 것과 같습니다.
엔진이 제대로 회전하는지, 출력은 충분한지만 검증합니다. 반면 통합 테스트는 엔진을 자동차에 장착하고 실제로 도로를 달려보는 것입니다.
변속기, 바퀴, 핸들이 모두 함께 작동하는지 확인합니다. 과거에는 이 두 종류의 테스트를 모두 수작업으로 작성해야 했습니다.
유닛 테스트는 비교적 간단했지만, 통합 테스트는 복잡했습니다. 데이터베이스를 모킹해야 하고, 외부 API 호출을 가짜로 만들어야 했습니다.
테스트 하나 작성하는 데 실제 코드보다 더 많은 시간이 걸리기도 했습니다. 개발자들은 종종 통합 테스트를 포기하고 유닛 테스트만 작성했습니다.
바로 이런 어려움을 해결하기 위해 LLM 기반 자동 테스트 생성이 주목받고 있습니다. LLM은 코드의 의존성을 분석하여 어떤 부분을 모킹해야 하는지 자동으로 파악합니다.
데이터베이스 연결이 필요하면 pytest의 fixture를 활용한 목 객체를 생성해줍니다. API 호출이 있다면 responses 라이브러리를 사용한 모킹 코드를 작성해줍니다.
개발자는 생성된 테스트를 약간만 수정하면 됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.
2번째 줄에서 pytest를 임포트합니다. pytest는 파이썬에서 가장 널리 사용되는 테스트 프레임워크입니다.
5-7번째 줄은 VIP 등급을 구매 금액 기준으로 테스트합니다. 100만원 정확히, 그리고 150만원으로 두 가지 케이스를 검증합니다.
9-12번째 줄은 구독 연수 기준 VIP 등급을 테스트합니다. 14-17번째 줄은 경계값 테스트로, 등급이 바뀌는 경계선을 검증합니다.
실제 현업에서는 어떻게 활용할까요? 스타트업에서 결제 시스템을 개발한다고 가정해봅시다.
결제 함수는 PG사 API를 호출하고, 데이터베이스에 거래 내역을 저장하며, 사용자에게 이메일을 발송합니다. 이런 복잡한 함수의 통합 테스트를 수작업으로 작성하려면 하루 이상 걸릴 수 있습니다.
하지만 LLM에게 코드를 입력하고 "통합 테스트를 작성해줘"라고 요청하면, 모든 외부 의존성을 모킹한 테스트가 몇 초 만에 생성됩니다. 하지만 주의할 점도 있습니다.
LLM이 생성한 목 객체가 실제 외부 시스템의 동작과 완전히 일치하지 않을 수 있습니다. 예를 들어 PG사 API가 특정 상황에서 반환하는 에러 코드를 LLM이 정확히 알지 못할 수 있습니다.
따라서 통합 테스트는 반드시 실제 환경이나 스테이징 환경에서도 실행해봐야 합니다. 김개발 씨는 LLM이 생성한 유닛 테스트와 통합 테스트를 실행해보았습니다.
모든 테스트가 통과했습니다. "이제 자신 있게 코드 리뷰를 받을 수 있겠어요!" 유닛 테스트와 통합 테스트 자동 생성을 활용하면 테스트 작성 시간을 80% 이상 단축할 수 있습니다.
두 종류의 테스트를 균형 있게 작성하여 견고한 코드베이스를 만들어보세요.
실전 팁
💡 - 유닛 테스트는 빠르게 실행되어야 하므로 모든 외부 의존성을 모킹하세요.
- 통합 테스트는 실제 환경과 최대한 유사하게 설정하되, 테스트 데이터베이스를 사용하세요.
- pytest의 parametrize 데코레이터를 활용하면 여러 케이스를 간결하게 작성할 수 있습니다.
3. Edge Case 자동 발견
테스트를 실행한 김개발 씨는 안심했지만, 선배 박시니어 씨가 질문을 던졌습니다. "음수 금액이 들어오면 어떻게 되죠?
구독 연수가 100년이면요?" 김개발 씨는 당황했습니다. 그런 경우는 전혀 생각하지 못했던 것입니다.
엣지 케이스는 정상 범위를 벗어나는 극단적인 입력값이나 예외 상황을 의미합니다. LLM은 코드를 분석하여 음수, 0, 매우 큰 값, null, 특수문자 등 개발자가 놓치기 쉬운 엣지 케이스를 자동으로 발견하고 테스트를 생성합니다.
다음 코드를 살펴봅시다.
# LLM이 발견한 엣지 케이스 테스트
def test_edge_cases_negative_values():
# 음수 입력 처리
with pytest.raises(ValueError):
calculate_user_grade(-1000, 3)
with pytest.raises(ValueError):
calculate_user_grade(500000, -1)
def test_edge_cases_zero_values():
# 0 값 처리
assert calculate_user_grade(0, 0) == "BRONZE"
def test_edge_cases_extreme_values():
# 극단적으로 큰 값
assert calculate_user_grade(999999999999, 0) == "VIP"
assert calculate_user_grade(0, 1000) == "VIP"
김개발 씨는 얼굴이 빨개졌습니다. 박시니어 씨의 질문에 제대로 답하지 못했기 때문입니다.
"음수요? 그건...
데이터베이스에 음수가 저장되지 않으니 괜찮지 않을까요?" 박시니어 씨가 고개를 저었습니다. "API를 통해 직접 호출될 수도 있잖아요.
악의적인 사용자가 일부러 이상한 값을 보낼 수도 있고요." 그렇다면 엣지 케이스란 정확히 무엇일까요? 쉽게 비유하자면, 엣지 케이스는 마치 다리의 하중 테스트와 같습니다.
일반적으로는 자동차 몇 대가 지나가지만, 만약 수십 대의 트럭이 동시에 지나간다면 어떻게 될까요? 아무도 타지 않은 상태에서는요?
이런 극단적인 상황을 미리 테스트하는 것이 엣지 케이스 테스트입니다. 엣지 케이스를 고려하지 않으면 어떤 일이 벌어질까요?
2021년, 한 유명 전자상거래 사이트에서 가격에 음수를 입력하면 오히려 돈을 받는 버그가 발견되었습니다. 개발자가 음수 입력을 검증하지 않았기 때문입니다.
또 다른 사례로, 특정 게임에서 레벨을 255 이상으로 올리면 0으로 되돌아가는 버그도 있었습니다. 이는 변수의 최대값을 고려하지 않았기 때문입니다.
바로 이런 문제를 방지하기 위해 엣지 케이스 자동 발견이 중요합니다. LLM은 코드를 분석하여 가능한 모든 엣지 케이스를 추론합니다.
숫자 입력이라면 음수, 0, 매우 큰 수를 테스트합니다. 문자열이라면 빈 문자열, 매우 긴 문자열, 특수문자를 포함한 문자열을 검증합니다.
배열이라면 빈 배열, 단일 요소 배열, 매우 큰 배열을 테스트합니다. 개발자가 일일이 생각하기 어려운 케이스들을 자동으로 찾아내는 것입니다.
위의 코드를 한 줄씩 살펴보겠습니다. 3-6번째 줄은 음수 입력 테스트입니다.
pytest.raises는 예외가 발생하는지 확인합니다. 음수 금액이나 음수 구독 연수가 입력되면 ValueError가 발생해야 합니다.
8-10번째 줄은 0 값 테스트입니다. 아무것도 구매하지 않고 신규 가입한 사용자는 BRONZE 등급이어야 합니다.
12-15번째 줄은 극단적으로 큰 값을 테스트합니다. 정수 오버플로우가 발생하지 않는지 확인합니다.
실제 현업에서는 어떻게 활용할까요? 금융 서비스를 개발하는 팀이 있다고 가정해봅시다.
송금 함수에 0원, 음수, 1000억원 같은 극단값이 입력되면 어떻게 될까요? 계좌번호에 특수문자가 들어가면요?
이런 엣지 케이스를 모두 수작업으로 찾아내려면 며칠이 걸릴 수 있습니다. 하지만 LLM에게 코드를 분석시키면, 10분 안에 수십 개의 엣지 케이스를 발견할 수 있습니다.
하지만 주의할 점도 있습니다. LLM이 발견한 모든 엣지 케이스가 실제로 처리되어야 하는 것은 아닙니다.
비즈니스 요구사항에 따라 일부 엣지 케이스는 무시해도 됩니다. 예를 들어 구독 연수가 1000년인 경우는 현실적으로 불가능하므로 테스트하지 않아도 됩니다.
개발자의 판단이 필요합니다. 김개발 씨는 LLM에게 엣지 케이스 발견을 요청했습니다.
결과를 보고 깜짝 놀랐습니다. 총 15개의 엣지 케이스가 발견되었고, 그중 8개는 현재 코드에서 제대로 처리되지 않고 있었습니다.
급히 코드를 수정하여 검증 로직을 추가했습니다. 엣지 케이스 자동 발견을 활용하면 프로덕션 환경에서 발생할 수 있는 버그를 사전에 예방할 수 있습니다.
완벽한 코드는 없지만, 최대한 많은 상황을 테스트하여 견고한 시스템을 만들어보세요.
실전 팁
💡 - 엣지 케이스 중 비즈니스적으로 불가능한 것은 과감히 제외하세요.
- 발견된 엣지 케이스는 코드에 입력 검증 로직을 추가하는 계기로 삼으세요.
- 보안 관련 엣지 케이스(SQL Injection, XSS 등)는 특히 주의 깊게 테스트하세요.
4. 테스트 실행과 피드백 루프
테스트를 모두 작성한 김개발 씨는 실행해보았습니다. 그런데 5개의 테스트가 실패했습니다.
당황한 김개발 씨에게 박시니어 씨가 말했습니다. "실패한 테스트를 다시 LLM에게 보여주면, 문제를 분석하고 수정 방법을 제안해줄 거예요."
테스트 피드백 루프는 테스트 실패 결과를 LLM에게 전달하여 원인을 분석하고 수정 방안을 제시받는 과정입니다. 실패한 테스트의 에러 메시지, 스택 트레이스, 예상값과 실제값을 LLM이 분석하여 코드 수정을 제안합니다.
이 과정을 반복하면 테스트 통과율을 빠르게 높일 수 있습니다.
다음 코드를 살펴봅시다.
# 테스트 실패 예시
FAILED test_edge_cases_negative_values - AssertionError:
Expected ValueError but got BRONZE
# LLM이 제안한 수정 코드
def calculate_user_grade(purchase_amount, years_subscribed):
# 입력값 검증 추가
if purchase_amount < 0:
raise ValueError("구매 금액은 음수일 수 없습니다")
if years_subscribed < 0:
raise ValueError("구독 연수는 음수일 수 없습니다")
# 기존 등급 계산 로직
if purchase_amount >= 1000000 or years_subscribed >= 5:
return "VIP"
# ... 나머지 로직
김개발 씨는 테스트 실행 결과를 보며 한숨을 쉬었습니다. 빨간색으로 표시된 FAILED가 다섯 개나 보였습니다.
"이걸 다 어떻게 고치지? 에러 메시지를 읽어봐도 뭐가 문제인지 잘 모르겠는데..." 박시니어 씨가 옆에서 말했습니다.
"실패한 테스트 결과를 그대로 LLM한테 보여주세요. 원인을 분석하고 고치는 방법까지 알려줄 거예요." 테스트 피드백 루프는 어떻게 작동할까요?
쉽게 비유하자면, 테스트 피드백 루프는 마치 과외 선생님과 공부하는 것과 같습니다. 문제를 풀고 채점을 받으면, 선생님이 틀린 부분을 짚어주고 왜 틀렸는지 설명해줍니다.
그리고 어떻게 풀어야 하는지 힌트를 줍니다. LLM도 마찬가지로 실패한 테스트를 보고 원인을 분석하며, 수정 방법을 제안합니다.
피드백 루프 없이 개발하면 어떤 문제가 생길까요? 개발자는 실패한 테스트를 하나하나 디버깅해야 합니다.
로그를 읽고, 브레이크포인트를 설정하고, 변수값을 확인하는 과정이 반복됩니다. 간단한 버그는 금방 찾지만, 복잡한 로직 오류는 몇 시간씩 걸릴 수 있습니다.
특히 초보 개발자는 에러 메시지 해석조차 어려워할 수 있습니다. 바로 이런 비효율을 개선하기 위해 LLM 기반 피드백 루프가 활용됩니다.
개발자는 실패한 테스트의 에러 메시지와 스택 트레이스를 LLM에게 전달합니다. LLM은 에러 유형을 파악하고, 어느 부분에서 문제가 발생했는지 찾아냅니다.
그리고 구체적인 코드 수정안을 제시합니다. 개발자는 제안된 수정안을 적용하고 다시 테스트를 실행합니다.
이 과정을 반복하면 점차 테스트 통과율이 높아집니다. 위의 코드를 한 줄씩 살펴보겠습니다.
1-2번째 줄은 실제 테스트 실패 메시지입니다. ValueError가 발생할 것으로 예상했지만 실제로는 BRONZE가 반환되었습니다.
5-7번째 줄에서 LLM이 제안한 수정 사항은 입력값 검증 로직 추가입니다. 음수 구매 금액이 들어오면 ValueError를 발생시킵니다.
9-11번째 줄도 마찬가지로 음수 구독 연수를 검증합니다. 13-16번째 줄부터는 기존 로직이 그대로 유지됩니다.
실제 현업에서는 어떻게 활용할까요? CI/CD 파이프라인을 구축한 팀이 있다고 가정해봅시다.
코드를 푸시하면 자동으로 테스트가 실행되고, 실패한 테스트가 있으면 빌드가 중단됩니다. 이때 실패한 테스트 결과를 LLM에게 자동으로 전달하고 분석 리포트를 받을 수 있습니다.
개발자는 출근해서 이메일을 확인하면, 어떤 테스트가 왜 실패했고 어떻게 고쳐야 하는지 이미 정리된 리포트를 받게 됩니다. 하지만 주의할 점도 있습니다.
LLM의 제안이 항상 최선은 아닙니다. 때로는 근본 원인이 아닌 증상만 해결하는 수정안을 제시할 수 있습니다.
예를 들어 null 체크를 추가하는 대신, 애초에 null이 발생하지 않도록 로직을 수정하는 것이 더 나을 수 있습니다. 개발자는 제안된 수정안을 비판적으로 검토해야 합니다.
김개발 씨는 LLM의 제안대로 입력값 검증 로직을 추가했습니다. 테스트를 다시 실행하자 5개 중 4개가 통과했습니다.
남은 1개도 LLM의 추가 분석을 통해 해결했습니다. 모든 테스트가 초록불로 바뀌었습니다.
테스트 피드백 루프를 활용하면 디버깅 시간을 대폭 줄이고, 테스트 주도 개발(TDD)을 더 쉽게 실천할 수 있습니다. 실패를 두려워하지 말고, 피드백을 통해 성장하세요.
실전 팁
💡 - 에러 메시지뿐 아니라 전체 스택 트레이스를 LLM에게 제공하면 더 정확한 분석을 받을 수 있습니다.
- 여러 테스트가 동시에 실패하면, 가장 먼저 실패한 테스트부터 해결하세요.
- LLM의 제안이 이해되지 않으면, 왜 그런 수정이 필요한지 추가 설명을 요청하세요.
5. 실습 pytest 테스트 생성기 만들기
이론을 배운 김개발 씨는 직접 테스트 생성기를 만들어보고 싶었습니다. 박시니어 씨가 말했습니다.
"Claude API를 사용하면 간단하게 만들 수 있어요. 함수 코드를 입력하면 자동으로 pytest 테스트를 생성하는 도구를 만들어볼까요?"
pytest 테스트 생성기는 함수 코드를 입력받아 자동으로 pytest 형식의 테스트 코드를 생성하는 도구입니다. Claude API를 활용하여 코드 분석, 테스트 케이스 추론, pytest 문법으로 작성하는 과정을 자동화합니다.
생성된 테스트는 파일로 저장되어 즉시 실행할 수 있습니다.
다음 코드를 살펴봅시다.
import anthropic
import sys
def generate_pytest(function_code):
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# Claude에게 테스트 생성 요청
message = client.messages.create(
model="claude-sonnet-4-5-20250929",
max_tokens=2000,
messages=[{
"role": "user",
"content": f"다음 함수의 pytest 테스트를 작성해주세요:\n\n{function_code}"
}]
)
return message.content[0].text
# 사용 예시
code = """
def calculate_user_grade(purchase_amount, years_subscribed):
if purchase_amount >= 1000000 or years_subscribed >= 5:
return "VIP"
elif purchase_amount >= 500000 or years_subscribed >= 3:
return "GOLD"
elif purchase_amount >= 100000:
return "SILVER"
return "BRONZE"
"""
test_code = generate_pytest(code)
print(test_code)
김개발 씨는 이제 직접 도구를 만들어볼 차례였습니다. "매번 웹에서 Claude에게 복사-붙여넣기 하는 것보다, 커맨드라인에서 바로 실행할 수 있으면 훨씬 편할 것 같아요." 박시니어 씨가 고개를 끄덕였습니다.
"좋은 생각이에요. 파이썬 스크립트로 간단하게 만들 수 있습니다.
Claude API를 호출하는 코드만 작성하면 돼요." pytest 테스트 생성기는 어떻게 만들까요? 쉽게 비유하자면, 테스트 생성기는 마치 자동 번역기와 같습니다.
한국어를 입력하면 영어로 번역해주듯이, 함수 코드를 입력하면 테스트 코드로 변환해줍니다. 핵심은 Claude API를 호출하는 부분입니다.
API에게 명확한 지시를 내리면, 원하는 형식의 테스트가 생성됩니다. 이런 도구가 없다면 어떨까요?
개발자는 함수를 작성할 때마다 브라우저를 열고, Claude 웹사이트에 접속하고, 코드를 복사-붙여넣기 해야 합니다. 생성된 테스트를 다시 복사해서 IDE에 붙여넣어야 합니다.
이 과정이 하루에 수십 번 반복되면 상당한 시간 낭비입니다. 자동화가 절실합니다.
바로 이런 불편을 해소하기 위해 커맨드라인 테스트 생성기를 만듭니다. 파이썬으로 간단한 스크립트를 작성하면 됩니다.
anthropic 라이브러리를 설치하고, API 키를 설정하고, 함수 코드를 읽어서 Claude에게 전달합니다. Claude는 몇 초 안에 pytest 테스트를 생성하여 반환합니다.
생성된 테스트는 자동으로 파일에 저장되거나 터미널에 출력됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.
1-2번째 줄에서 필요한 라이브러리를 임포트합니다. anthropic은 Claude API 클라이언트입니다.
4-5번째 줄에서 함수를 정의하고 API 클라이언트를 초기화합니다. API 키는 환경변수나 설정 파일에서 읽어오는 것이 안전합니다.
8-15번째 줄에서 Claude에게 메시지를 보냅니다. model 파라미터에는 사용할 모델을 지정하고, messages에는 요청 내용을 작성합니다.
17번째 줄에서 응답에서 텍스트 부분만 추출하여 반환합니다. 20-29번째 줄은 사용 예시입니다.
calculate_user_grade 함수 코드를 문자열로 준비합니다. 31번째 줄에서 generate_pytest 함수를 호출하여 테스트를 생성하고, 32번째 줄에서 결과를 출력합니다.
실제 현업에서는 어떻게 활용할까요? 팀에서 이런 도구를 공유하면 모든 개발자가 활용할 수 있습니다.
커맨드라인에서 "pytest-gen my_function.py"처럼 실행하면 자동으로 테스트 파일이 생성됩니다. CI/CD 파이프라인에 통합하여, 새로운 함수가 추가될 때마다 자동으로 기본 테스트를 생성할 수도 있습니다.
구글, 페이스북 같은 대기업에서는 이미 유사한 도구를 내부적으로 사용하고 있습니다. 하지만 주의할 점도 있습니다.
API 호출에는 비용이 발생합니다. 함수 하나당 몇 센트 수준이지만, 수천 개의 함수를 처리하면 비용이 누적됩니다.
또한 API 응답 시간이 네트워크 상태에 따라 달라질 수 있으므로, 타임아웃 처리를 추가하는 것이 좋습니다. 민감한 코드를 외부 API에 전송하는 것이 우려된다면, 로컬에서 실행 가능한 오픈소스 LLM을 사용하는 방법도 있습니다.
김개발 씨는 스크립트를 실행해보았습니다. 몇 초 만에 완벽한 pytest 테스트가 생성되었습니다.
"이제 테스트 작성이 정말 간편해졌어요! 팀원들한테도 공유해야겠어요." pytest 테스트 생성기를 만들어 팀 전체의 생산성을 높여보세요.
작은 자동화 도구가 큰 변화를 만들어냅니다.
실전 팁
💡 - API 키는 절대 코드에 하드코딩하지 말고 환경변수로 관리하세요.
- 생성된 테스트를 파일로 저장할 때는 기존 테스트를 덮어쓰지 않도록 주의하세요.
- argparse를 사용하여 커맨드라인 인자를 받으면 더 유연한 도구를 만들 수 있습니다.
6. 실습 TDD 워크플로 자동화
마지막으로 김개발 씨는 TDD 워크플로 전체를 자동화하고 싶었습니다. 박시니어 씨가 말했습니다.
"테스트 작성, 실행, 피드백, 코드 수정까지 모두 자동으로 진행되는 시스템을 만들어볼까요?"
TDD 워크플로 자동화는 테스트 주도 개발의 전체 사이클을 자동으로 실행하는 시스템입니다. 함수 스펙을 입력하면 자동으로 테스트를 생성하고, 실행하고, 실패한 부분을 분석하여 코드를 수정합니다.
이 과정이 모든 테스트가 통과할 때까지 반복됩니다.
다음 코드를 살펴봅시다.
import subprocess
import anthropic
def tdd_automation(function_spec):
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# 1단계: 스펙으로부터 테스트 생성
test_code = generate_test_from_spec(client, function_spec)
save_file("test_function.py", test_code)
# 2단계: 초기 구현 생성 (실패할 것으로 예상)
impl_code = generate_initial_impl(client, function_spec)
save_file("function.py", impl_code)
max_iterations = 5
for i in range(max_iterations):
# 3단계: 테스트 실행
result = run_pytest()
if "passed" in result and "failed" not in result:
print(f"성공! {i+1}번째 반복에서 모든 테스트 통과")
break
# 4단계: 실패 분석 및 코드 수정
fixed_code = fix_code_with_llm(client, impl_code, result)
save_file("function.py", fixed_code)
impl_code = fixed_code
return impl_code
def run_pytest():
# pytest 실행하고 결과 반환
result = subprocess.run(
["pytest", "test_function.py", "-v"],
capture_output=True, text=True
)
return result.stdout + result.stderr
김개발 씨는 이제 궁극의 자동화를 꿈꾸었습니다. "테스트도 자동으로 만들고, 코드도 자동으로 작성되고, 실패하면 자동으로 고쳐지는...
그런 시스템이 가능할까요?" 박시니어 씨가 웃으며 답했습니다. "가능합니다.
그게 바로 TDD 워크플로 자동화예요. 물론 완벽하진 않지만, 초기 구현을 빠르게 만드는 데는 아주 유용하죠." TDD 워크플로 자동화는 어떻게 동작할까요?
쉽게 비유하자면, TDD 자동화는 마치 자율주행 자동차와 같습니다. 목적지(함수 스펙)를 입력하면, 차가 알아서 길을 찾고(테스트 생성), 운전하고(코드 작성), 장애물을 만나면 피해가며(에러 수정) 목적지까지 도착합니다.
개발자는 중간중간 모니터링만 하면 됩니다. TDD를 수동으로 진행하면 어떤 과정을 거칠까요?
전통적인 TDD는 레드-그린-리팩터 사이클입니다. 먼저 실패하는 테스트를 작성합니다(레드).
그 테스트를 통과하는 최소한의 코드를 작성합니다(그린). 코드를 개선합니다(리팩터).
이 사이클을 기능이 완성될 때까지 반복합니다. 하나의 함수를 완성하는 데 이 사이클을 10-20번 반복할 수 있습니다.
시간이 많이 소요되고, 집중력도 필요합니다. 바로 이런 반복 작업을 자동화하기 위해 LLM 기반 TDD 워크플로가 등장했습니다.
개발자는 함수의 스펙만 작성합니다. "사용자 등급을 계산하는 함수를 만들어줘.
구매 금액과 구독 연수를 받아서 VIP, GOLD, SILVER, BRONZE 중 하나를 반환해." 이 스펙을 시스템에 입력하면, 자동으로 테스트가 생성되고, 초기 구현이 작성되고, 테스트가 실행됩니다. 실패한 테스트가 있으면 LLM이 분석하여 코드를 수정합니다.
이 과정이 모든 테스트가 통과할 때까지 자동으로 반복됩니다. 위의 코드를 한 줄씩 살펴보겠습니다.
4-5번째 줄에서 메인 함수를 정의하고 Claude 클라이언트를 초기화합니다. 8-9번째 줄에서 함수 스펙으로부터 테스트를 생성하고 파일로 저장합니다.
12-13번째 줄에서 초기 구현을 생성합니다. 이 구현은 아직 완벽하지 않아 일부 테스트가 실패할 것입니다.
15-27번째 줄은 반복 루프입니다. 최대 5번까지 반복하며, 그 안에서 테스트를 실행하고 결과를 확인합니다.
20-22번째 줄에서 모든 테스트가 통과하면 성공 메시지를 출력하고 종료합니다. 25-27번째 줄에서 실패한 테스트가 있으면 LLM에게 에러 메시지를 보내서 코드를 수정받습니다.
31-37번째 줄의 run_pytest 함수는 subprocess를 사용하여 실제 pytest 명령을 실행합니다. capture_output=True로 설정하여 테스트 결과를 텍스트로 받아옵니다.
실제 현업에서는 어떻게 활용할까요? 스타트업에서 신규 기능을 빠르게 프로토타이핑할 때 유용합니다.
기획자가 요구사항을 문서로 작성하면, 개발자는 그것을 함수 스펙으로 변환하여 TDD 자동화 시스템에 입력합니다. 몇 분 안에 기본적인 구현과 테스트가 완성됩니다.
개발자는 생성된 코드를 리뷰하고 비즈니스 로직을 세밀하게 조정하는 데 집중할 수 있습니다. 하지만 주의할 점도 있습니다.
자동화 시스템이 생성한 코드는 완벽하지 않습니다. 비즈니스 로직의 미묘한 부분이나 성능 최적화는 사람이 직접 수정해야 합니다.
또한 자동화에만 의존하면 개발자의 문제 해결 능력이 떨어질 수 있습니다. 자동화는 도구일 뿐, 최종 책임은 개발자에게 있다는 것을 잊지 말아야 합니다.
김개발 씨는 TDD 자동화 시스템을 실행해보았습니다. 함수 스펙을 입력하고 기다리자, 3번의 반복 끝에 모든 테스트가 통과했습니다.
생성된 코드를 보니 거의 완벽했고, 몇 줄만 수정하면 프로덕션에 바로 배포할 수 있을 수준이었습니다. "이제 정말 TDD가 부담스럽지 않네요.
테스트 작성 시간을 걱정하지 않아도 되니까, 더 많은 기능에 TDD를 적용할 수 있을 것 같아요." 박시니어 씨가 만족스러운 표정으로 말했습니다. "좋아요.
하지만 기억하세요. 자동화는 도구일 뿐입니다.
생성된 코드를 항상 비판적으로 검토하고, 테스트가 정말 의미 있는지 판단해야 합니다." TDD 워크플로 자동화를 활용하면 개발 속도와 코드 품질을 동시에 높일 수 있습니다. 하지만 맹목적으로 따르지 말고, 도구를 현명하게 사용하는 개발자가 되세요.
실전 팁
💡 - 자동화 시스템의 반복 횟수를 제한하여 무한 루프를 방지하세요.
- 생성된 코드와 테스트는 반드시 코드 리뷰를 거쳐야 합니다.
- 복잡한 비즈니스 로직은 자동화보다 수동 작성이 더 나을 수 있습니다. 상황에 맞게 선택하세요.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
ReAct 패턴 마스터 완벽 가이드
LLM이 생각하고 행동하는 ReAct 패턴을 처음부터 끝까지 배웁니다. Thought-Action-Observation 루프로 똑똑한 에이전트를 만들고, 실전 예제로 웹 검색과 계산을 결합한 강력한 AI 시스템을 구축합니다.
AI 에이전트의 모든 것 - 개념부터 실습까지
AI 에이전트란 무엇일까요? 단순한 LLM 호출과 어떻게 다를까요? 초급 개발자를 위해 에이전트의 핵심 개념부터 실제 구현까지 이북처럼 술술 읽히는 스타일로 설명합니다.
프로덕션 RAG 시스템 완벽 가이드
검색 증강 생성(RAG) 시스템을 실제 서비스로 배포하기 위한 확장성, 비용 최적화, 모니터링 전략을 다룹니다. AWS/GCP 배포 실습과 대시보드 구축까지 프로덕션 환경의 모든 것을 담았습니다.
RAG 캐싱 전략 완벽 가이드
RAG 시스템의 성능을 획기적으로 개선하는 캐싱 전략을 배웁니다. 쿼리 캐싱부터 임베딩 캐싱, Redis 통합까지 실무에서 바로 적용할 수 있는 최적화 기법을 다룹니다.
실시간으로 답변하는 RAG 시스템 만들기
사용자가 질문하면 즉시 답변이 스트리밍되는 RAG 시스템을 구축하는 방법을 배웁니다. 실시간 응답 생성부터 청크별 스트리밍, 사용자 경험 최적화까지 실무에서 바로 적용할 수 있는 완전한 가이드입니다.