필자는 1년차 프론트엔드 개발자로서 스타트업에 근무 중으로 극악의 스케줄이었던 정부과제가 마무리되고, 해당 프로젝트를 회고하고 리팩토링하면서 관심이 갔던 테스트코드에 대해서 이야기 해보려 한다.
이때까지 자사서비스를 유지보수할 때는 사내 백엔드 개발자와 소통하며 작업했기때문에 DTO를 함께 정하고 그대로 작업하고, 개발서버를 붙이면서 작업을 해가는 과정이었다.
하지만 정부 과제를 하면서 두 곳의 타사의 API를 받아서 해당 정보를 사용할 일이 있었는데,
마감 전 A사의 API의 가이드라인만 나왔을 때는 msw
로 해당 API를 목킹하여 작업을 진행했고 추후 API를 연결하고 msw
를 제거하면서 작업을 이어갔다.
마감 이후에는 바쁜 일정이 끝나고, 그나마 여유로운 시기에 MUI 제거 후 직접 구현, 레거시 코드 수정 등의 리팩토링 작업을 하고 있었는데 이때 내 눈에 들어온 영상이 프론트엔드 개발에서의 테스트 코드였다.
이 영상이 말하는 장점을 짧게 요약하자면
- 비지니스 로직을 쭉 짜고 Hot Module Reloading을 기다리고 넘어가는 테스크 사이클이 있을 경우 바로 확인 가능 → 피드백 사이클이 짧아져 생산성이 높아진다.
- 비지니스 로직에만 집중할 수 있다. (격리한다)
- 외부 의존성이 복잡한 경우(외부 개발사의 서버가 안열려 있을 경우) 잘 목킹해두면 정말 검증하고 싶은 부분만 좁혀서 테스트 가능하다.
- 코드를 다 짜고 방어용으로 짜는 안정성(신뢰감)
- 라이브러리 버전을 올리거나, 리팩토링할 경우 (이전에는 되었던 로직이 되는지 안되는지 손으로 클릭해서 확인할 필요가 없다.)
- 일종의 문서가 될 수 있음 (초기 의사 결정에 따라서 작성된 테스트코드이므로)
필자도 이 영상을 보기전까지는 직접적으로 테스트코드의 필요성을 느낄 일도 없었고 현재 회사에서 작성하고 있지않기때문에 궁금해하고만 있었는데, 이 영상을 보고나서는 우리 회사에서의 문제점을 해결해주는데에 테스트코드가 필요하겠다는 생각을 가지게 되었다. 이후 인프런에서 테스트 코드 강의를 보고 자사서비스에 브랜치를 파서 적용해보기도 했다.
그러던 중 클라이언트의 요청으로 이전에 했던 정부과제를 안정화하여 재배포해야할 상황이 생겼다.
우리 백엔드 서버와 통신하는 부분은 사내 백엔드 개발자와 함께 개발서버에서 작업을 하고 로컬에서 확인해 볼 수 있었지만, B사의 SSO 정보를 가져와서 사용하는 부분은 실서버에 올리지않고는 파악하기 어려운 부분이 있었다.
말아서 올리고 오류가 발생하면 하나 고치고 다시 배포하고를 반복했다고 하셨다. 프론트의 경우 한번 말아서 올리는데만 2,30분이 걸리고, 새벽에만 실서버에 배포할 수 있었기때문에 다들 피로한 상태에서 작업하다보니 집중력이 떨어져서 더 이런 문제가 발생했던거 같다.
다음날 나를 포함한 다른 프론트 팀원도 해당 부분을 해결하려고 코드를 확인하였는데, 여기에 JEST를 사용해서 B사의 API를 목킹해서 데이터가 잘 들어오는지 파악할 수 있겠다는 생각이 들었고, 테스트 코드를 아래와 같이 작성했다.
test('유효한 토큰이 있을 때 SSO 정보를 가져와 상태를 업데이트한다', async () => {
(getCookie as jest.Mock).mockReturnValue(false); // 토큰이 없는 상태로 설정
// window.location.href에 code가 포함된 URL을 설정하여 목킹
delete window.location;
window.location = {
href: 'http://localhost?code=mockCode',
} as any;
//B사 API의 가짜 응답을 설정
const mockTokenResponse = {
data: {
data: { access_token: 'mockAccessToken' },
},
};
const mockUserInfoResponse = {
data: {
data: {
email: 'test@example.com',
fullname: 'Test User',
id: 1,
locale: 'en',
phone: '123456789',
profile_url: 'https://example.com/profile.jpg',
},
},
};
(axios.post as jest.Mock).mockResolvedValue(mockTokenResponse); // SSO의 mock 응답 설정
(axios.get as jest.Mock).mockResolvedValue(mockUserInfoResponse); // uerInfo의 mock 응답 설정
// Provider를 렌더링하고, Context.Consumer를 사용해 context 데이터 검증
render(
<Provider>
<Context.Consumer>
{(value) => (
<div>
{value?.email}, {value?.fullname}
</div>
)}
</Context.Consumer>
</Provider>
);
// context가 업데이트된 후 올바른 사용자 정보가 화면에 표시되는지 확인
await waitFor(() => {
expect(screen.getByText('test@example.com, Test User')).toBeInTheDocument();
});
});
위 코드를 통해서 전날 벽 우리 팀원분들을 괴롭혔던 부분을 만날 수 있었다. 좀 더 빨리 작성했었더라면 좋았겠지만 이 때의 짜릿함은 잊을 수 없다!!😛
이렇게 외부 개발사의 api를 사용하지만 msw
로 별도로 목킹하기에는 규모 대비 비용이 더 들 때,
잘 목킹하여 테스트코드를 써두면 비지니스 로직은 분리되므로 각각에 더 집중할 수 있다는 장점2를 확실히 체감할 수 있었다!!
솔직히 필요성을 느끼지 못하면 공부할 마음도 잘 생기지않게 되는데 직접 회사에서 적용하면서 체감하다보니 큰 동기가 되었고, 프론트팀 코드리뷰시간에 해당 부분을 공유했을 때 다들 좋게 봐주셨고, 앞으로 외부 개발사와 일하는 경우에는 해당 부분만이라도 테스트코드를 작성하자는 분위기를 이끌어낼 수 있었다!🤗🤗