이전 이야기 : https://thepin.tistory.com/205
제5화. 데이터와 진심
점심시간의 소동 이후, 나는 투명 인간이 되기로 자처했다.
도수 없는 블루라이트 차단 안경을 썼다. 그것은 내 눈을 가리는 얇은 방패이자, 세상과의 단절을 선언하는 벽이었다. 사람들과 대화할 때는 미간이나 인중을 보며 철저히 시선을 피했다.
최 주임은 나를 피해 다녔고, 다른 동료들도 나를 어려워하는 기색이 역력했다. 휴게실에서 마주치면 어색하게 고개를 돌렸고, 내 뒤에서 수군거리는 소리가 들리는 듯했다.
‘차라리 이게 나아. 아무도 내 눈을 보지 않으면, 아무 일도 일어나지 않아.’
나는 모니터 속으로 도피했다. 내 눈이 닿아도 안전한 건, 오직 0과 1로 이루어진 데이터 세상뿐이었다. 그곳에는 감정도, 오해도, 왜곡된 기억도 없었다. 오직 명확한 논리(Logic)만이 존재했다.
“이번 주 금요일까지 QA(품질 보증) 1차수 완료해야 합니다. 다들 야근 각오하세요.”
박성우 팀장의 선포에 사무실 곳곳에서 앓는 소리가 터져 나왔다. 이번 프로젝트는 쇼핑몰 플랫폼의 대규모 업데이트였다. 문제는 테스트해야 할 상품 옵션 조합이 수만 가지에 달한다는 점이었다.
“이걸 언제 다 눌러봐? 사람 손으로 하다가 손가락 나가겠다.”
옆자리의 윤서아 대리도 한숨을 쉬며 엑셀 시트를 넘겼다. 화면에는 테스트해야 할 케이스(Test Case)가 끝도 없이 나열되어 있었다. 단순 반복 노동. 개발자들에게는 지옥과도 같은 시간이었다.
나는 조용히 내 할당량을 체크했다. 3,000건. 일일이 클릭해서 장바구니에 담고, 결제 금액이 맞는지 확인해야 했다.
‘이걸 손으로 하는 건 비효율적이야.’
문득 면접 때 박 팀장에게 했던 말이 떠올랐다. “효율적인 시간 관리와 집중력으로 승부하겠습니다.”
그때는 억지로 지어낸 말이었지만, 지금은 증명해야 했다. 내가 괴물이 아니라, 쓸모 있는 팀원이라는 것을.
나는 퇴근 시간이 지나도록 자리에 남았다. 사무실 불이 하나둘 꺼지고, 윤 대리마저 “한결 씨, 안 가요? 적당히 하고 가요”라며 퇴근했을 때, 나는 비로소 본격적인 작업을 시작했다.
어두운 사무실, 모니터 불빛만이 내 얼굴을 비췄다. 나는 심호흡을 한 번 하고 코드 에디터(VS Code)를 실행했다. 검은색 배경에 커서가 하얗게 깜빡였다.
마치 빈 캔버스 앞에 선 화가처럼, 나는 머릿속으로 로직을 그렸다.
‘엑셀 파일을 읽는다. 브라우저를 연다. 값을 입력한다. 결과를 확인한다.’
손가락이 키보드 위를 춤추기 시작했다. 타닥타닥, 경쾌한 타건음이 정적을 갈랐다.
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
웹 브라우저를 자동으로 제어하는 Selenium 라이브러리를 불러왔다. 엑셀에 있는 테스트 케이스를 읽어와서, 자동으로 브라우저를 띄우고 버튼을 클릭하게 만드는 스크립트를 짜기 시작했다.
‘로그인하고, 상품 검색하고, 옵션 선택하고….’
코드를 한 줄 한 줄 짤 때마다 잡념이 사라졌다. 내 눈은 코드를 쫓느라 바빴고, 머릿속은 논리로 가득 찼다. 여기에는 감정이 개입할 틈이 없었다. 오직 입력과 출력, 원인과 결과만이 존재했다.
새벽 2시.
“됐다.”
엔터키를 누르자, 화면 속 브라우저가 혼자서 빠르게 움직이기 시작했다. 상품을 담고, 결제 페이지로 넘어가고, 금액을 검증하는 과정이 눈 깜짝할 사이에 지나갔다.
사람이 하면 1분 걸릴 일이 3초 만에 끝났다. 나는 의자에 등을 기대며 마른세수를 했다. 피곤했지만, 가슴 한구석이 벅차올랐다.
다음 날 아침 회의 시간.
“진척도 체크하겠습니다. 윤 대리, 얼마나 했어?”
“어제 야근해서 500건 정도 했습니다. 오늘 더 속도 내보겠습니다.”
박 팀장은 고개를 끄덕이더니 나를 쳐다봤다.
“이한결 씨는? 신입이라 속도 안 나는 건 이해하는데, 그래도 일정은 맞춰야 합니다.”
나는 말없이 USB를 모니터에 꽂고 화면을 띄웠다.
“제 할당량 3,000건, 테스트 완료했습니다.”
회의실에 정적이 흘렀다. 박 팀장이 미간을 찌푸렸다.
“뭐라고요? 장난합니까? 어제 저녁부터 오늘 아침까지 그걸 다 했다고? 대충 체크하고 넘긴 거 아니에요?”
“아닙니다. 자동화 스크립트를 짰습니다.”
나는 준비해둔 결과 리포트를 화면에 띄웠다. 성공(Pass) 2,980건, 실패(Fail) 20건. 실패한 케이스에 대한 로그 분석까지 깔끔하게 정리되어 있었다.
“파이썬 셀레니움으로 브라우저 구동을 자동화했고, 결과값은 엑셀로 다시 저장되게 만들었습니다. 제가 직접 검수한 샘플링 결과와 100% 일치합니다.”
박 팀장은 입을 벌린 채 화면과 나를 번갈아 쳐다봤다. 윤 대리도 놀란 눈으로 내 코드를 훑어보고 있었다.
“이거… 네가 직접 짠 거야?”
“네. 입사 전에 공부했던 걸 응용해봤습니다.”
박 팀장이 헛기침을 하며 안경을 고쳐 썼다. 그는 깐깐하게 리포트를 검토하더니, 이내 고개를 들었다. 이번에는 경멸도, 의심도 없었다.
“허… 대단하네. 신입이 이 정도까지 할 줄은 몰랐는데.”
그는 나를 똑바로 바라보며 말했다.
“잘했어, 이한결. 덕분에 팀 전체 일정이 3일은 당겨지겠네. 이 스크립트, 윤 대리랑 공유해서 다른 파트에도 적용해.”
“네, 알겠습니다.”
“그리고… 오해해서 미안하다. 일머리는 확실히 있네.”
그 순간, 가슴 속에서 묵직한 것이 울렸다.
그것은 내 능력을 썼을 때 상대방이 보여주는 멍한 복종과는 달랐다.
나를 두려워하는 공포의 눈빛과도 달랐다.
그것은 ‘인정’이었다.
내가 조작하지 않은, 상대방의 마음에서 우러나온 진짜 데이터였다.
‘이거구나.’
나는 책상 아래로 주먹을 꽉 쥐었다. 눈을 쓰지 않아도 된다. 아니, 눈을 쓰지 않아야만 얻을 수 있는 것이 있다.
“감사합니다, 팀장님.”
나는 처음으로 고개를 들고 박 팀장의 눈을 마주 보며 웃었다. 내 눈동자는 그저 평범한 갈색으로 빛나고 있었다.

다음 이야기 : https://thepin.tistory.com/208
소설001: 내 눈을 보면 안 돼 - 제6화. 불신의 그림자
제6화. 불신의 그림자파이썬 자동화 스크립트 덕분에 나는 팀 내에서 ‘일 잘하는 신입’으로 자리를 잡아가고 있었다. 하지만 아이러니하게도, 업무 능력이 빛을 발할수록 나를 둘러싼 그림자
thepin.tistory.com
[부록] 한결이 작성한 QA 자동화 스크립트 (python_script.py)
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import time
import datetime
# 설정: 엑셀 파일 경로 및 결과 저장 경로
INPUT_FILE = 'qa_test_cases.xlsx'
OUTPUT_FILE = f'qa_result_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx'
# 웹드라이버 설정 (Chrome)
options = webdriver.ChromeOptions()
options.add_argument('--headless') # 브라우저 창을 띄우지 않고 실행 (속도 향상)
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=options)
def run_test_automation():
print(">>> QA 자동화 테스트를 시작합니다...")
# 엑셀 파일 로드
try:
df = pd.read_excel(INPUT_FILE)
except FileNotFoundError:
print(f"Error: {INPUT_FILE} 파일을 찾을 수 없습니다.")
return
results = []
logs = []
# 테스트 케이스 순회
for index, row in df.iterrows():
case_id = row['CaseID']
url = row['TargetURL']
expected_text = row['ExpectedResult']
print(f"Testing [{case_id}]...", end=" ")
try:
driver.get(url)
# 페이지 로딩 대기 (최대 10초)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# 결과 검증 (페이지 소스 내에 기대하는 텍스트가 있는지 확인)
body_text = driver.find_element(By.TAG_NAME, "body").text
if expected_text in body_text:
results.append("Pass")
print("PASS")
else:
results.append("Fail")
logs.append(f"[{case_id}] Fail: Expected '{expected_text}' not found.")
print("FAIL")
except Exception as e:
results.append("Error")
logs.append(f"[{case_id}] Error: {str(e)}")
print("ERROR")
# 결과 저장
df['TestResult'] = results
df.to_excel(OUTPUT_FILE, index=False)
print("\n>>> 테스트 완료.")
print(f"Total: {len(df)}, Pass: {results.count('Pass')}, Fail: {results.count('Fail')}")
print(f"결과 파일 저장됨: {OUTPUT_FILE}")
if logs:
print("\n[Error Logs]")
for log in logs:
print(log)
driver.quit()
if __name__ == "__main__":
run_test_automation()'VibeCoding > 글' 카테고리의 다른 글
| 소설001: 내 눈을 보면 안 돼 - 제7화. 오해의 대가 (0) | 2026.02.18 |
|---|---|
| 소설001: 내 눈을 보면 안 돼 - 제6화. 불신의 그림자 (0) | 2026.02.18 |
| 소설001: 내 눈을 보면 안 돼 - 제4화. 점심시간의 갈등 (0) | 2026.02.18 |
| 소설001: 내 눈을 보면 안 돼 - 제4.5화. 틈새의 악의 (0) | 2026.02.18 |
| 소설001: 내 눈을 보면 안 돼 - 제3화. 첫 출근의 불안 (0) | 2026.02.18 |



