Skip to Content
Step2B-1. UI 테스트 작성 — 테스트를 위해 프로덕션 코드를 바꿔도 될까?

B-1. UI 테스트 작성 — 테스트를 위해 프로덕션 코드를 바꿔도 될까?

이렇게 읽어보세요: 선배 크루의 고민 → 토론 질문을 먼저 읽고 → AS-IS 코드를 직접 분석 → 리뷰어의 피드백으로 관점 확인 → 탐색 미션에서 PR 깊이 파기

선배 크루의 고민

“테스트를 통과시키려고 프로덕션 코드에 optional chaining(?.)을 추가했는데, 이게 맞는 건지 찝찝합니다. 테스트 환경에서 DOM이 없어서 null이 되는 걸 우회한 건데…” — 하루, PR #33 

“추가하다가 문득… 테스트를 구현하기 위해 LottoListprivate methodpublic으로 변경해야겠다고 생각이 들었는데, 이런 경우 public으로 메소드를 풀어야 하나요? 아니면 다른 방식이 또 있을까요?” — 준찌, PR #121 

“calculateRankHistory()는 내부에서만 사용되지만, 테스트 때문에 어쩔 수 없이 public으로 놔뒀습니다. 궁금한 점은 테스트만을 위해 특정 메서드를 public으로 유지하는 경우도 있나요? 아니면 더 좋은 방법이 있을까요?” — 기린, PR #356 

이 코드를 보면서 이야기해봅시다

  • getLottoRateOfReturn()은 수익률을 계산하는 순수한 로직인데, 테스트하려면 DOM이 필요한 구조입니다. 어떻게 분리하면 DOM 없이 테스트할 수 있을까요?”
  • “optional chaining은 문제를 해결한 걸까요, 숨긴 걸까요?”

AS-IS 코드

출처: PR #33 — 하루 (2021, 2단계)  · 해당 파일 

// components/ResultModal.js — 테스트 통과를 위해 프로덕션 코드에 optional chaining을 추가 export default class ResultModal { constructor({ isVisible, lottoTickets, winningNumber, onRestart }) { this.$modal = $('.modal'); this.$modalClose = $('.modal-close'); this.attachEvents(); } attachEvents() { // 테스트 환경에서 DOM이 없어서 null → optional chaining으로 우회 this.$modalClose?.addEventListener('click', this.closeModal.bind(this)); this.$resetButton?.addEventListener('click', () => { this.onRestart(); this.closeModal(); }); } // 이 메서드를 테스트하고 싶지만, 생성자에서 DOM을 찾으므로 // 테스트 환경에서는 에러가 발생한다 getLottoRateOfReturn() { const profit = this.lottoTickets.reduce( (acc, lottoTicket) => acc + WINNING_PRIZE[lottoTicket.totalMatchCount].PRIZE, 0 ); const loss = this.lottoTickets.length * LOTTO_PRICE; return getRateOfReturn(profit, loss); } }

리뷰어의 피드백

“테스트를 위해 프로덕션 코드에 trick이 가해지는 상황은 없어야 합니다!” — PR #33 (링크 )

“도메인 폴더의 퍼블릭 메소드와 constants를 이용해보세요. 테스트에서 private 메서드에 접근할 필요가 없도록 설계하는 것이 중요합니다.” — PR #121 (링크 )

“테스트 코드를 위해 접근 제어자를 변경하는 것은 지양해야 합니다. public 인터페이스를 통해 테스트할 수 있도록 구조를 고민해보세요.” — PR #356 (링크 )


Last updated on