- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Featured Post
작성자:
Iros
- 공유 링크 만들기
- X
- 이메일
- 기타 앱

요즘 개발자들끼리 이야기하다 보면 AI 바이브 코딩이라는 말, 진짜 자주 나오죠. 저도 20년 넘게 IT 현장에서 개발하고 운영하고 장애도 맞아보고… 뭐 별일을 다 겪으면서 살아왔는데요. 솔직히 요즘처럼 개발 방식이 확 바뀌는 시기는 흔치 않았던 것 같아요.
예전에는 검색하고, 문서 뒤지고, Stack Overflow 보면서 한 줄 한 줄 맞춰가던 시간이 꽤 길었잖아요. 그런데 이제는 ChatGPT나 Claude 같은 LLM에게 “이 기능 만들어줘”, “이 테스트 코드 짜줘”라고 말하면 꽤 그럴듯한 코드가 툭 나옵니다. 처음 보면 약간 허탈하기도 해요. 내가 몇 시간 걸릴 일을 얘는 몇 초 만에 하네? 싶어서요.
근데 말이죠. 시간이 조금 지나고 나면 또 다른 생각이 듭니다. “어? 이거 그냥 믿고 쓰면 안 되겠는데?” 하는 순간이 와요. 특히 Playwright 같은 E2E 테스트를 AI에게 맡겨보면 그 느낌이 더 선명해집니다. 겉보기엔 코드가 멀쩡해요. 테스트도 뭔가 있어 보이고요. 그런데 막상 실행해보면 이상한 버튼을 누르거나, 아직 뜨지도 않은 모달을 기다리거나, 사용자는 절대 가지 않을 경로로 테스트를 만들어놓는 경우가 꽤 많습니다.
그래서 오늘은 이 이야기를 좀 편하게 해보려고 해요. AI 코딩 시대에 Playwright E2E 테스트를 어떻게 바라봐야 하는지, LLM을 쓰면서 토큰을 아끼는 방법, 프롬프트를 덜 낭비하면서 더 잘 쓰는 방식, 그리고 playwright.config.ts에 미리 세팅해두면 두고두고 편한 팁까지요. 딱딱한 강의 느낌 말고, 그냥 개발 오래 한 형이 커피 한 잔 놓고 얘기해주는 느낌으로 가볼게요.
Playwright는 클릭 자동화 도구가 아니라 사용자 흐름을 보는 도구예요
Playwright를 처음 접하면 보통 이렇게 생각하기 쉽습니다. “브라우저 띄우고, 버튼 클릭하고, 입력하고, 결과 확인하는 도구구나.” 맞아요. 틀린 말은 아닙니다. 그런데 그 정도로만 이해하면 Playwright를 반쯤만 쓰는 거라고 저는 생각해요.
실무에서 E2E 테스트가 진짜 의미 있는 순간은 단순히 버튼이 눌리는지 확인할 때가 아니거든요. 사용자가 우리 서비스를 실제로 어떻게 지나가는지, 그 여정이 중간에 끊기지 않는지 보는 게 핵심입니다. 로그인하고, 상품을 검색하고, 장바구니에 담고, 쿠폰을 적용하고, 결제 직전까지 가는 흐름. 이런 걸 하나의 이야기처럼 검증하는 거죠.
생각해보면 사용자는 우리 코드의 내부 구조를 모릅니다. 버튼의 class 이름이 뭔지도 모르고, 컴포넌트가 몇 개로 나뉘어 있는지도 관심 없어요. 그냥 “로그인 버튼이 보여야 하고”, “클릭하면 다음 화면으로 넘어가야 하고”, “결제 완료 후 주문번호가 보여야” 합니다. Playwright 테스트도 결국 그 관점으로 짜야 오래 갑니다.
그런데 AI가 만든 테스트 코드는 종종 개발자 내부 시선에 너무 가깝습니다. 예를 들면 이런 식이죠.
await page.click('.login-btn');
await page.fill('#email', 'test@test.com');
await page.fill('#password', 'password123');
물론 돌아갈 수도 있어요. 근데 실무에서는 이런 셀렉터가 생각보다 잘 깨집니다. CSS class는 디자인 변경하면서 바뀌기도 하고, id는 리팩터링하면서 정리되기도 하니까요. 그럼 테스트가 기능 문제도 아닌데 자꾸 실패합니다. 아… 이거 은근히 사람 지치게 해요.
저는 가능하면 사용자에게 보이는 의미를 기준으로 잡는 편입니다. 예를 들면 getByRole, getByLabel, getByText, 또는 프로젝트에서 약속한 data-testid를 쓰는 식이죠.
await page.getByRole('button', { name: '로그인' }).click();
await page.getByLabel('이메일').fill('test@test.com');
await page.getByLabel('비밀번호').fill('password123');
이렇게 하면 테스트 코드가 훨씬 사람 말에 가까워집니다. 나중에 다른 개발자가 봐도 “아, 로그인 버튼 누르고 이메일이랑 비밀번호 넣는구나” 하고 바로 이해해요. 테스트 코드는 기계만 읽는 게 아니라, 결국 동료 개발자와 미래의 내가 읽는 문서이기도 하거든요.
AI가 만든 테스트 코드, 그럴듯하지만 은근히 위험한 부분들
솔직히 AI에게 Playwright 테스트를 만들어달라고 하면 꽤 잘 만들어줍니다. 예전 같으면 문서 열어놓고 한참 봐야 했던 코드도 금방 나오고요. 그래서 저는 AI를 안 쓰자는 이야기를 하고 싶은 게 전혀 아닙니다. 오히려 적극적으로 씁니다. 다만, 그대로 믿고 붙여 넣는 건 위험하다는 말을 하고 싶은 거예요.
AI가 특히 자주 하는 실수가 있습니다. 바로 기다림 처리를 대충 한다는 거예요. 예를 들어 결제 완료 후 주문번호가 나와야 하는 화면에서 AI는 종종 이런 코드를 만들어냅니다.
await page.waitForTimeout(3000);
await expect(page.locator('.order-number')).toBeVisible();
처음 보면 별문제 없어 보이죠. 3초 기다리고 주문번호가 보이는지 확인하는 코드니까요. 그런데 이 방식은 실무에서 꽤 골치 아픕니다. 어떤 날은 서버가 빨라서 0.5초 만에 뜨고, 어떤 날은 외부 결제 API가 느려서 5초 걸립니다. 그럼 테스트가 랜덤하게 실패해요. 이런 테스트를 우리는 보통 flaky test라고 부르죠. 진짜 팀 분위기 흐립니다. 테스트를 믿을 수 없게 되니까요.
저라면 조금 다르게 씁니다.
await expect(page.getByText(/주문번호/)).toBeVisible();
await expect(page.getByTestId('order-number')).toHaveText(/\d+/);
이렇게 하면 “그냥 3초 기다려”가 아니라 “주문번호라는 의미 있는 결과가 화면에 나타날 때까지 기다려”가 됩니다. 이 차이가 생각보다 커요. 테스트가 훨씬 안정적이고, 실패했을 때 원인도 더 잘 보입니다.
또 하나, AI는 종종 waitForSelector를 남발합니다. 물론 필요한 경우가 있습니다. 하지만 Playwright는 기본적으로 locator와 expect 조합이 꽤 똑똑하게 기다려줍니다. 굳이 여기저기 waitForSelector를 박아두면 테스트는 느려지고, 코드도 지저분해져요. 뭐랄까, 급한 마음에 테이프를 여기저기 붙여놓은 느낌이랄까요.
저는 AI가 만든 테스트 코드를 받을 때 꼭 이런 기준으로 다시 봅니다.
- 사용자 행동 기준으로 작성됐는지 확인합니다. 내부 class나 DOM 구조에 너무 의존하면 오래 못 갑니다.
- 기다림이 의미 기반인지 봅니다. waitForTimeout처럼 시간으로 때우는 코드는 최대한 줄이는 게 좋아요.
- 검증이 진짜 비즈니스 결과를 보고 있는지 확인합니다. 버튼 클릭 여부보다 “로그인 후 사용자 이름이 보이는지”가 더 중요할 때가 많습니다.
- 테스트 데이터가 서로 충돌하지 않는지 봅니다. 병렬 실행을 켜면 이 부분이 바로 터집니다.
실제로 제가 한 프로젝트에서 AI가 만들어준 테스트를 거의 그대로 넣었다가, CI에서만 실패하는 상황을 겪은 적이 있어요. 로컬에서는 멀쩡한데 GitHub Actions에서만 간헐적으로 깨지는 거죠. 결국 원인은 고정된 테스트 계정을 여러 테스트가 동시에 쓰면서 세션이 꼬인 거였고, 그 뒤로는 테스트 데이터 생성과 격리를 먼저 챙기게 됐습니다. 이건 문서보다 한 번 당해보면 바로 몸에 새겨져요…
LLM으로 Playwright 코드를 만들 때 토큰을 아끼는 프롬프트 방식
AI를 쓰다 보면 은근히 신경 쓰이는 게 토큰입니다. 특히 긴 코드 붙여넣고, 에러 로그 붙이고, 다시 고쳐달라고 하고, 또 전체 파일을 보여주고… 이러다 보면 금방 맥락이 무거워져요. 응답도 느려지고, 답변 품질도 오히려 떨어지는 느낌이 납니다.
제 경험상 LLM을 잘 쓰는 핵심은 한 번에 다 맡기지 않는 것입니다. 이게 참 아이러니하죠. AI가 똑똑해졌으니 전부 맡기고 싶어지는데, 실제로는 작게 쪼개서 시키는 게 훨씬 결과가 좋습니다.
예를 들어 이런 프롬프트는 별로 추천하지 않습니다.
우리 쇼핑몰 서비스의 로그인, 상품 검색, 장바구니, 쿠폰 적용, 결제까지 Playwright E2E 테스트 전체를 작성해줘.
이렇게 던지면 AI는 열심히 뭔가를 만들긴 합니다. 그런데 대부분 추측이 많이 들어갑니다. URL도 추측하고, 버튼 이름도 추측하고, 상태 관리도 추측해요. 그러다 보니 내가 원하는 코드와는 조금씩 어긋납니다. 결국 다시 설명해야 하고, 토큰은 더 씁니다. 약간 “빨리 가려다가 더 돌아가는” 상황이 됩니다.
차라리 이렇게 작게 나누는 편이 낫습니다.
Playwright로 로그인 E2E 테스트만 작성해줘.
조건은 아래와 같아.
- 테스트 대상 URL: /login
- 이메일 input은 data-testid="email-input"
- 비밀번호 input은 data-testid="password-input"
- 로그인 버튼은 data-testid="login-button"
- 로그인 성공 후 /dashboard로 이동해야 함
- expect 기반으로 검증해줘
- waitForTimeout은 쓰지 말아줘
이 정도면 AI가 훨씬 덜 헤맵니다. 불필요한 상상도 줄고, 결과물도 바로 쓸 가능성이 높아져요. 그리고 중요한 건, 이렇게 프롬프트를 쓰면 토큰도 아낍니다. 코드 전체를 던지지 않고 필요한 맥락만 주는 거니까요.
프롬프트에 프로젝트 규칙을 미리 박아두면 꽤 편합니다
저는 AI에게 Playwright 코드를 요청할 때, 프로젝트 공통 규칙을 거의 템플릿처럼 붙여둡니다. 매번 길게 설명하기 귀찮으니까요. 예를 들면 이런 식입니다.
우리 프로젝트의 Playwright 테스트 작성 규칙은 다음과 같아.
- TypeScript 사용
- test와 expect는 @playwright/test에서 import
- 셀렉터는 getByRole, getByLabel, getByTestId 순서로 우선 사용
- CSS selector는 꼭 필요할 때만 사용
- waitForTimeout 사용 금지
- 테스트 이름은 한국어로 작성
- 로그인은 helper 함수 loginAsUser(page)를 사용
이걸 한 번 잘 만들어두면 프롬프트 품질이 확 올라갑니다. 사실 이게 별거 아닌 것 같아도, 매번 “waitForTimeout 쓰지 마”, “CSS class 쓰지 마”, “TypeScript로 해줘”라고 말하는 것도 은근히 귀찮거든요. 인간도 반복 업무 싫어하는데 AI한테 시킬 때도 반복 설명 줄이는 게 좋습니다.
저는 개인적으로 자주 쓰는 프롬프트 조각을 메모 앱에 따로 저장해둡니다. “Playwright 테스트 생성용”, “에러 로그 분석용”, “리팩터링용”, “테스트 안정화용” 이런 식으로요. 출장 가는 기차 안에서도 노트북 열고 작업할 때가 있는데, 그때 이 템플릿 덕을 꽤 봤습니다. 시간이 애매하게 30분 남았을 때 전체를 고민하는 게 아니라, 딱 한 테스트만 고치는 식으로 접근하면 묘하게 일이 잘 풀리더라고요.
토큰을 아끼려면 코드 전체를 던지지 말고 문제만 잘라서 보여주세요
개발하다 보면 AI에게 에러를 물어보고 싶을 때가 많죠. 그때 많은 분들이 파일 전체를 통째로 붙여 넣습니다. 저도 처음엔 그랬어요. “자, 다 줄 테니까 네가 알아서 봐줘” 느낌으로요. 그런데 이 방식은 편해 보이지만, 토큰을 엄청 먹습니다. 그리고 AI도 중요한 부분을 놓칠 때가 있습니다.
Playwright 테스트가 실패했다면, 보통 필요한 정보는 생각보다 많지 않습니다.
- 실패한 테스트 코드 일부
- 에러 메시지
- 실패한 locator 또는 expect 구문
- 현재 화면에서 실제로 보이는 텍스트나 DOM 일부
- 원래 기대한 사용자 흐름
이 정도만 줘도 AI는 꽤 잘 봅니다. 예를 들어 이렇게 질문하는 거죠.
아래 Playwright 테스트가 CI에서만 실패해.
원인은 locator 문제인지, 타이밍 문제인지 봐줘.
waitForTimeout을 쓰지 않는 방향으로 고쳐줘.
[실패 코드]
...
[에러 메시지]
...
[실제 화면 상태]
로그인 버튼 클릭 후 2단계 인증 모달이 뜨는 경우가 있음
이렇게 물어보면 AI가 훨씬 실무적인 답을 줍니다. 특히 “CI에서만 실패한다”, “2단계 인증 모달이 뜨는 경우가 있다” 같은 맥락은 아주 중요합니다. AI는 우리 서비스를 직접 본 적이 없으니까요. 우리가 그 눈을 빌려줘야 합니다.
뭐랄까, LLM은 뛰어난 주니어 개발자 같기도 합니다. 손은 빠르고 지식도 많은데, 우리 회사 서비스의 사정은 모릅니다. 그래서 일을 잘 시키려면 “이 프로젝트에서는 이런 일이 자주 생겨”라는 배경을 짧고 정확하게 알려줘야 해요. 그게 토큰도 아끼고 결과도 좋아지는 길입니다.
playwright.config.ts에 미리 넣어두면 테스트 삶이 편해지는 설정들
playwright.config.ts는 생각보다 중요합니다. 처음에는 그냥 기본 설정으로 시작해도 됩니다. 그런데 테스트가 늘어나고 CI에 올라가고, 여러 브라우저나 모바일 뷰포트까지 챙기기 시작하면 설정 파일의 차이가 꽤 크게 느껴져요.
AI에게 “Playwright config 만들어줘”라고 하면 보통 기본적인 설정을 만들어줍니다. 나쁘진 않아요. 하지만 실무에서는 조금 더 다듬어야 합니다. 저는 특히 retries, timeout, trace, screenshot, fullyParallel, baseURL 쪽을 꼭 봅니다.
retries와 timeout은 환경별로 다르게 보는 게 좋습니다
로컬에서는 테스트가 한 번에 실패해도 바로 고치면 됩니다. 그런데 CI에서는 네트워크나 서버 상태 때문에 아주 가끔 흔들릴 때가 있어요. 그래서 저는 CI 환경에서는 retries를 1이나 2 정도 주는 편입니다. 로컬에서는 0으로 두고요. 그래야 진짜 문제를 빨리 발견할 수 있습니다.
retries: process.env.CI ? 2 : 0,
timeout: 30 * 1000,
timeout도 너무 길게 잡으면 실패를 늦게 알게 되고, 너무 짧게 잡으면 정상 흐름도 실패합니다. 보통 기본은 30초 정도로 두고, 결제나 외부 API가 끼는 테스트는 개별 테스트에서 조금 늘리는 식이 좋습니다.
test('결제 완료 후 주문번호가 표시된다', async ({ page }) => {
test.setTimeout(60 * 1000);
...
});
이런 작은 설정 하나가 나중에 CI 시간을 많이 아껴줍니다. 테스트가 실패했는데 5분씩 멍하니 기다리는 상황, 진짜 아깝거든요. 커피 한 잔 뽑아올 시간이라고 생각하면 괜찮을 수도 있지만… 매일 반복되면 그건 좀 슬픕니다.
trace와 screenshot은 always보다 on-first-retry가 현실적입니다
Playwright의 trace는 정말 좋은 기능입니다. 실패한 테스트를 나중에 열어보면 어떤 페이지에서 어떤 클릭을 했고, 어디서 실패했는지 꽤 자세히 볼 수 있어요. 문제는 이걸 항상 켜두면 파일이 엄청 쌓인다는 겁니다.
AI가 만들어주는 설정에서는 종종 screenshot이나 trace를 always로 켜놓는 경우가 있습니다. 처음에는 좋아 보이죠. 모든 테스트 기록이 남으니까요. 그런데 테스트가 많아지면 저장 공간도 부담되고, CI artifact도 무거워집니다.
저는 보통 이렇게 둡니다.
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
}
이렇게 하면 평소에는 가볍게 돌고, 문제가 생겼을 때만 필요한 자료가 남습니다. 실무에서는 이 균형이 중요해요. 모든 걸 다 남기면 마음은 편한데, 시스템은 피곤해집니다.
fullyParallel은 빠르지만 테스트 데이터 격리가 먼저입니다
fullyParallel을 켜면 테스트 실행 시간이 확 줄어드는 경우가 많습니다. 테스트 파일이 여러 개일 때 병렬로 돌기 때문이죠. 체감이 꽤 큽니다. 10분 걸리던 게 3~4분으로 줄어들면 괜히 기분 좋습니다.
fullyParallel: true,
그런데 여기엔 조건이 있습니다. 테스트들이 서로 같은 데이터를 건드리면 안 됩니다. 같은 계정으로 로그인해서 장바구니를 수정한다든지, 같은 주문 데이터를 삭제한다든지 하면 병렬 실행에서 바로 문제가 생깁니다. 로컬에서는 괜찮다가 CI에서만 이상하게 깨지는 대표적인 원인이기도 합니다.
그래서 병렬 실행을 하려면 테스트 데이터 전략이 먼저입니다.
- 테스트마다 고유한 사용자 계정을 만들거나
- API로 테스트 데이터를 생성하고 정리하거나
- 읽기 전용 테스트와 쓰기 테스트를 분리하거나
- serial로 돌려야 할 테스트는 명확히 분리하는 식이 필요합니다.
AI는 fullyParallel을 쉽게 추천하지만, 이런 데이터 충돌까지 완벽히 고려하진 못합니다. 이 지점이 바로 개발자의 경험이 필요한 부분이에요. 도구를 빠르게 만드는 건 AI가 도와줄 수 있지만, 테스트가 팀 안에서 안정적으로 굴러가게 만드는 건 결국 사람이 판단해야 합니다.
Page Object Model은 귀찮아 보여도 나중에 나를 살려줍니다
Playwright 테스트가 몇 개 안 될 때는 그냥 테스트 파일 안에 locator를 다 적어도 괜찮습니다. 그런데 테스트가 20개, 50개, 100개로 늘어나면 얘기가 달라져요. 로그인 버튼 이름 하나 바뀌었는데 테스트 파일 30개를 고쳐야 한다? 그날은 그냥 기분이 좀 그렇습니다.
그래서 저는 어느 정도 규모가 생기면 Page Object Model을 추천합니다. 쉽게 말하면, 페이지별로 자주 쓰는 동작과 요소를 클래스로 묶어두는 방식입니다.
export class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.page.getByTestId('email-input').fill(email);
await this.page.getByTestId('password-input').fill(password);
await this.page.getByTestId('login-button').click();
}
}
테스트에서는 이렇게 쓰면 됩니다.
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('test@test.com', 'password123');
await expect(page).toHaveURL(/dashboard/);
이렇게 해두면 테스트 코드가 훨씬 읽기 쉬워집니다. “어떤 selector를 눌렀는지”보다 “무슨 행동을 했는지”가 드러나거든요. 이게 E2E 테스트에서는 꽤 중요합니다. 테스트가 문서처럼 읽히기 시작하면 유지보수 난이도가 확 내려갑니다.
AI에게도 Page Object Model 기준으로 요청하면 결과물이 더 좋아집니다. 그냥 “로그인 테스트 짜줘”보다 “LoginPage 클래스를 만들고, 테스트에서는 그 클래스를 사용하게 해줘”라고 말하면 구조가 훨씬 안정적으로 나와요.
AI에게 맡길 것과 내가 직접 봐야 할 것을 나누는 감각
요즘은 AI가 코드를 워낙 잘 만들어주니까, 어디까지 맡겨야 할지 헷갈릴 때가 있습니다. 저도 그래요. 특히 바쁠 때는 그냥 “다 만들어줘” 하고 싶습니다. 그런데 실무에서 몇 번 당해보면 기준이 생깁니다.
제가 보기엔 AI에게 맡기기 좋은 일은 이런 쪽입니다.
- 기본 Playwright 테스트 구조 만들기
- 중복되는 helper 함수 초안 작성
- 에러 메시지 기반 원인 후보 정리
- 기존 테스트를 Page Object Model로 리팩터링하는 초안 만들기
- playwright.config.ts 기본 설정 생성
반대로 사람이 직접 봐야 하는 부분도 분명히 있습니다.
- 사용자 흐름이 실제 서비스와 맞는지
- 비즈니스적으로 중요한 검증이 빠지지 않았는지
- 테스트 데이터가 서로 충돌하지 않는지
- 셀렉터가 장기적으로 안정적인지
- CI 환경에서 실행 시간이 과하지 않은지
사실 이 구분만 잘해도 AI를 훨씬 편하게 쓸 수 있습니다. AI는 속도를 올려주는 도구고, 방향을 잡는 건 사람입니다. 이걸 반대로 하면 좀 피곤해져요. AI가 방향까지 잡게 두면 그럴듯한데 묘하게 엉뚱한 결과가 나옵니다. 마치 내비게이션이 빠른 길이라고 안내했는데, 막상 가보니 골목길에 트럭이 못 들어가는 그런 느낌이랄까요.
Playwright E2E 테스트는 결국 팀의 신뢰를 만드는 일입니다
저는 E2E 테스트를 단순히 QA 자동화 정도로만 보지 않습니다. 물론 버그를 잡는 것도 중요하죠. 그런데 더 크게 보면 팀이 배포를 믿고 할 수 있게 만드는 장치라고 생각합니다.
배포 버튼 누를 때마다 마음이 철렁하면 개발팀이 오래 못 버팁니다. “로그인은 되겠지?”, “결제는 괜찮겠지?”, “이번에 바꾼 UI 때문에 회원가입 깨진 건 아니겠지?” 이런 걱정이 계속 쌓이면 속도가 느려집니다. 반대로 핵심 사용자 흐름을 Playwright가 안정적으로 지켜주면 배포할 때 마음이 훨씬 가벼워져요.
물론 모든 걸 E2E 테스트로 덮을 필요는 없습니다. 그러면 테스트가 느려지고 관리가 힘들어집니다. 단위 테스트, 통합 테스트, E2E 테스트는 각자 역할이 있어요. Playwright는 그중에서도 사용자의 눈높이에서 “진짜 되는지” 보는 역할에 가깝습니다.
그래서 AI가 테스트 코드를 빨리 만들어준다고 해서, 그걸로 끝이라고 생각하면 조금 아쉽습니다. AI가 초안을 만들어주면 우리는 그 위에 실무 감각을 얹어야 합니다. 어떤 흐름이 진짜 중요한지, 어떤 검증이 빠지면 장애로 이어지는지, 어떤 설정이 CI 시간을 잡아먹는지. 이런 건 경험이 꽤 많이 들어갑니다.
AI 코딩 시대일수록 개발자의 촉은 더 중요해지는 것 같아요
AI가 코드를 짜주는 시대가 되니까 개발자의 역할이 사라지는 거 아니냐는 이야기도 종종 나오죠. 저는 조금 다르게 봅니다. 반복적인 코딩은 줄어들 수 있지만, 좋은 질문을 던지는 능력과 결과물을 판단하는 능력은 더 중요해졌다고 봐요.
Playwright E2E 테스트도 마찬가지입니다. AI가 테스트 코드를 빨리 만들어줄 수는 있습니다. 하지만 그 테스트가 실제 사용자 흐름을 잘 담고 있는지, 너무 깨지기 쉬운 방식은 아닌지, CI에서 안정적으로 돌 수 있는지는 사람이 봐야 합니다. 특히 서비스의 맥락을 아는 개발자가요.
LLM을 쓸 때는 프롬프트를 작게 나누고, 프로젝트 규칙을 미리 알려주고, 코드 전체가 아니라 필요한 맥락만 잘라서 전달해보세요. 그리고 playwright.config.ts에는 retries, timeout, trace, screenshot, fullyParallel 같은 설정을 프로젝트 상황에 맞게 차근차근 다듬어두면 좋습니다. 한 번 귀찮게 정리해두면, 나중에 진짜 편합니다.
솔직히 저도 아직 매번 완벽하게 하진 못합니다. 바쁘면 대충 AI한테 던지고 싶은 날도 있고, 테스트 깨지면 “아 그냥 지워버릴까” 싶은 순간도 있어요. 그래도 오래 개발해보니 알겠더라고요. 잘 만든 테스트는 당장은 귀찮아도 나중에 팀을 살립니다. 특히 배포 직전 금요일 오후에요. 그때 초록색 테스트 결과를 보면, 괜히 마음이 든든합니다.
AI는 정말 좋은 동료가 됐습니다. 다만 그 동료에게 일을 잘 시키려면, 우리도 기준이 있어야 해요. Playwright도 마찬가지고요. 결국 좋은 E2E 테스트는 AI의 속도와 개발자의 경험이 같이 만났을 때 나오는 것 같습니다. 뭐, 이게 요즘 제가 느끼는 AI 바이브 코딩 시대의 현실적인 균형점이네요.
댓글
댓글 쓰기