-
과연 언제부터 프론트엔드에 테스트가 필요할까?Tip 2025. 7. 11. 11:56728x90반응형
과연 언제부터 프론트엔드에 테스트가 필요할까? 요즘 프론트엔드에서도 테스트는 필수인 것처럼 보입니다.
많은 회사에서 테스트코드 작성 경험을 우대 사항이나 필수 사항에 넣고 있으니까요.
하지만 제가 생각하기에 생각보다 많은 회사들은 프론트엔드에서의 테스트 도입을 못하고 있고, 안 하고 있다는 것을 많이 느낍니다.
이번 글에서 프론트엔드 관점에서 언제 테스트를 시작하면 좋을지에 대한 생각을 공유해 보겠습니다.
프론트엔드 단위 테스트: 언제 필요할까?
프론트엔드 분야에서 단위 테스트(Unit Test)의 필요성에 대해선 다양한 견해가 있습니다.
백엔드 로직과 달리 프론트엔드는 UI 표시와 상호작용이 많아서, 작은 단위까지 테스트를 작성하는 노력이 꼭 효율적이지 않을 때도 있습니다.
스토리북 같은 디자인 시스템을 도입하지 않는다면 프론트엔드 단위 테스트는 불필요하다는 의견에 저는 전적으로 동의합니다.
디자인 시스템(예: Storybook)을 사용하지 않고 개별 컴포넌트를 지속적으로 변경하는 단계에서는 단위 테스트가 유지보수 비용 대비 효용이 떨어질 수 있습니다.
그러나 디자인 시스템을 도입하고 컴포넌트 재사용성이 높아지는 단계에서는 각 컴포넌트의 단위 테스트나 스냅샷 테스트가 큰 가치를 발휘합니다.
Storybook의 play function과 Testing Library를 결합하면 사용자가 버튼을 클릭하거나 텍스트를 입력하는 상호작용을 Storybook 환경에서 시뮬레이션하고, 그 결과를 assertion으로 검증할 수 있습니다.
이렇게 하면 디자인 시스템의 모든 상태에 대한 테스트를 자동화하여 컴포넌트들을 안전하게 리팩터링 할 수 있습니다.게다가 Storybook 환경은 실제 브라우저 렌더링이므로, 단순 JSDOM 기반 테스트와 달리 화면 상태를 직접 눈으로 확인하면서 디버깅할 수 있다는 장점도 있습니다.
반대로, 아직 디자인 시스템 없이 개별 화면을 빠르게 만들고 있는 단계라면 굳이 모든 컴포넌트에 일일이 단위 테스트를 작성하기보다는 통합 테스트(Integration Test)나 E2E 테스트로 전체 흐름을 검증하는 편이 낫습니다.
예를 들어, 로그인 폼 컴포넌트를 따로 단위 테스트하기보다는, 실제 페이지에서 올바른 인증 흐름이 동작하는지를 E2E 테스트로 확인하고, 로그인 실패 시 에러 메시지가 표시되는지 등은 통합 테스트로 확인할 수 있습니다.
이렇게 하면 UI 세부 구현이 바뀌더라도 주요 시나리오가 깨지지만 않으면 테스트는 통과하므로, 자주 바뀌는 UI에 대한 테스트 유지보수 노력을 줄일 수 있습니다.
물론 프론트엔드 단위 테스트가 완전히 무의미한 것은 아닙니다.
로직이 있는 부분은 프론트엔드라도 엄연히 단위 테스트 가치가 있습니다.
대표적으로, 상태 관리 관련 로직이나 유틸 함수, 커스텀 훅(custom hook) 등은 입력값 대비 출력 또는 내부 상태 변화를 순수 함수 형태로 테스트하기 쉬운 경우가 많습니다.
예컨대 Zustand와 같은 상태 관리 라이브러리를 쓸 때도, 우리 애플리케이션이 정의한 상태 변화 함수(actions)가 의도대로 동작하는지 단위 테스트해 볼 수 있습니다.
단순히 Zustand의 동작을 검증할 필요는 없지만, 비즈니스 로직을 캡슐화한 store라면 그 액션 호출 결과 getState()가 예상대로 변하는지 테스트로 보호하면 추후 리팩토링에 도움이 됩니다.
React Query의 경우도 마찬가지입니다.
React Query 자체를 단위 테스트할 필요는 없지만, useQuery을 감싼 우리의 커스텀 훅이 있다면, 외부 API를 Mock Service Worker(MSW) 등으로 모킹 하여 데이터 로딩부터 화면 렌더링까지의 일련의 흐름을 테스트할 수 있습니다.
Testing Library와 MSW를 조합하면, 가짜 API 응답을 흉내 내서 로딩 스피너가 표시되었다가 데이터가 나타나는지, 에러 시 오류 메시지가 뜨는지 등을 손쉽게 검증할 수 있습니다.
이처럼 비동기 데이터 흐름이나 상태 변화는 통합 테스트 수준에서 검증하되, 복잡한 데이터 가공 로직이 있다면 그 부분만 별도 유틸 함수로 분리해 단위 테스트하는 방식을 권장합니다.
import { render, screen } from '@testing-library/react'; import Button from '@/components/ui/Button'; test('버튼이 props에 따라 올바르게 렌더링된다', () => { render(<Button variant="primary">Click me</Button>); const buttonElement = screen.getByRole('button', { name: /Click me/i }); expect(buttonElement).toHaveClass('btn-primary'); });
초기 스타트업 단계: 속도 vs. 안정성 딜레마
많은 프론트엔드 개발자들이 초기부터 테스트 코드를 적극적으로 작성해야 한다고 생각하지만, 현실적으로는 오히려 생산성을 떨어뜨립니다.
스타트업 초기 단계는 MVP(Minimum Viable Product)를 신속히 출시하고 사용자 피드백을 빠르게 받아 시장 적합성을 찾는 것이 가장 중요합니다.
실제로 많은 스타트업들이 Series A 투자를 받기 전까지는 테스트 코드를 거의 작성하지 않고, 주요 마일스톤을 달성한 이후에야 테스트를 본격 도입하는 경향이 있습니다.
Why Most Startups Don’t Write Unit Tests Until After Series A
In the chaotic, high-stakes world of startups, every decision feels like a make-or-break moment.
caffeinatedcoder.medium.com
테스트를 일찍부터 작성하면 제품의 버그 예방과 코드 품질 향상에 분명히 큰 도움이 되지만, 동시에 개발 시간과 테스트 코드 변경 등으로 시간을 낭비할 수밖에 없습니다.
반면 초기에 테스트를 생략하면 개발 속도는 올라가지만 코드베이스가 빠르게 커지면서 기술 부채와 리스크가 쌓일 수 있습니다.
요약하면, 스타트업 초반에는 제품 구현과 시장 검증이 우선이므로 테스트 작성이 뒤로 밀릴 수밖에 없다고 생각합니다.
특히 UI 변경이 잦고 기능 스펙이 불안정한 시기에는 테스트가 금방 무효화되기 쉽기 때문에, 시간을 들여 테스트를 작성하는 것이 낭비로 여겨질 수 있습니다.
초반에는 없던 실제 사용자와 중요한 데이터가 생기기 시작하는 시점에 테스트를 고민해도 늦지 않다고 생각합니다.
그리고 처음부터 모든 부분을 테스트하기보다는 핵심 로직 위주로 선택적으로 테스트 코드를 도입하는 것을 추천합니다.
import { renderHook, act } from '@testing-library/react'; import useAuthStore from '@/stores/useAuthStore'; test('로그인 액션이 제대로 상태를 업데이트한다', () => { const { result } = renderHook(() => useAuthStore()); act(() => { result.current.login({ username: 'testUser', token: 'fakeToken' }); }); expect(result.current.user.username).toBe('testUser'); });
제품 성장 단계: 안정성과 유지보수의 중요성
제품 시장 적합성(PMF)을 찾고, 고객 기반이 안정적으로 형성된 이후부터는 상황이 달라집니다.
이 시기부터는 기능 추가와 리팩토링이 빈번해지고, 한 번의 배포 실수가 심각한 장애로 이어질 수 있기 때문에 안정성과 유지보수가 중요해집니다.
이때부터 본격적으로 E2E 테스트를 구축하는 것이 좋다고 생각합니다.
특히 코드베이스가 커지면서 회귀 버그의 위험이 커집니다.
테스트를 생략한 채 기능 개발을 지속하면, 나중에는 도대체 어떤 변경이 어떤 기능을 망가뜨렸는지 파악하기 어려워져 개발 속도가 느려지고 품질이 떨어지는 문제가 있습니다.
특히 배포 안정성이 중요해지는 단계에서는 E2E 테스트의 가치가 부각됩니다.
E2E 테스트는 사용자의 실제 시나리오를 자동화해 중대한 기능이 끊임없이 동작하는지 확인해 주므로, 신규 릴리즈가 기존 핵심 기능(ex. 회원가입, 결제, 핵심 거래 기능 등)을 깨지 않도록 도와줍니다.
또 중요한 점은 조직이 커지고 여러 개발자가 동시에 프론트엔드 코드를 수정하는 상황에서는, 테스트가 없으면 새로운 사람이 코드베이스에 기여하거나 리팩터링 하기 겁이 납니다.
그리고 미래를 봤을 때, 좋은 테스트 문화가 있어야만 신규 개발자 온보딩도 수월해지고 코드 품질과 일관성을 유지하기 쉬워지는 단계라고 생각합니다.
실제로 페이스북도 초기에는 속도를 위해 다소 깨지는 것을 감수했지만, 회사가 성장하자 모토를 Move fast with stable infrastructure로 바꾸며 안정성 중시로 선회했습니다.
이렇듯 어느 규모 이상이 되면, 테스트를 하지 않는 게 시간 낭비인 상황이 발생합니다.import { test, expect } from '@playwright/test'; test('메인 페이지에서 로그인 프로세스 검증', async ({ page }) => { await page.goto('https://your-app.com'); await page.click('text=로그인'); await page.fill('input[name="username"]', 'testUser'); await page.fill('input[name="password"]', 'password'); await page.click('button[type="submit"]'); await expect(page.locator('text=환영합니다, testUser')).toBeVisible(); });
제 생각을 요약하자면, 초기 스타트업 단계에서는 테스트 코드 작성이 정말 필요한가 신중해야 됩니다.
이후 PMF 확보 후 성장 단계부터 본격적으로 필수적인 기능부터 E2E 도입하는 것이 좋다고 생각합니다.
디자인 시스템이 갖춰진 시점부터는 컴포넌트에 대한 단위 테스트를 도입하는 것이 좋다고 생각합니다.
테스트는 목적이 분명해야 합니다.
사이드 프로젝트가 아닌 회사라면 막연히 테스트를 작성하기보다는, 회사의 단계와 제품의 특성을 고려하여 전략적으로 접근하는 것이 중요하다고 생각합니다.
반응형'Tip' 카테고리의 다른 글
Module Federation을 활용한 마이크로 프론트엔드 구현 (0) 2025.07.14 Portal만 쓰시나요? HTML 표준 Dialog, Popover API 알아보기 (1) 2025.06.07 AI 크롤러 차단해서 요금 폭탄 방지하기 (0) 2025.05.25 PandaCSS vs Tailwind CSS vs Vanilla Extract 비교 분석 (2) 2025.05.11 Next.js와 Node.js 기반 실시간 대용량 편집기 Part4. 차세대 전송 및 AI 기술 (0) 2025.05.10