Skip to content

Conversation

@dudwntjs
Copy link
Collaborator

@dudwntjs dudwntjs commented Dec 26, 2025

계산기 만들기 (MVVM + DI + Unit Test)

  • Baemin 폴더는 안보셔도 되구요 Calculator 폴더만 보시면 됩니다‼️

의존성 주입

let service: CalculatorServicing = CalculatorService()
let viewModel = CalculatorViewModel(service: service)
let root = CalculatorViewController(viewModel: viewModel)
window.rootViewController = UINavigationController(rootViewController: root)

원래는 DI Container 써볼까 했는데,, 이해가 잘 안되구,,, 시간도 부족하고 해서ㅠㅠ
SceneDelegate에서 직접 의존성 조립합니다

사칙연산만 가능합니다🥹

  • ±, % 기능은 프로토콜에는 포함하지만 사칙연산 테스트가 더 중요한 것 같아서 no-op 처리햇습니다
    • 사실 구현하기 어려워서도 맞아여🫠
    • 그래도 따로 미리 빼놔서 나중에 추가하기도 편할 것 같아요 헤헤
    extension CalculatorServicing {
        func toggleSign() {}
        func percent() {}   
    }

NumberFormatter 이거 왜 있나용🤔

테스트 실행 환경의 Locale에 따라 숫자 문자열 포맷이 달라질 수 있다고 하더라구요!!
사실 저도 처음 겪은 트슈라서 공유합니다

  • 테스트 실행 환경의 로케일에 따라 숫자 표시가 달라져 Assertion이 흔들리는 문제를 원천 차단하기 위함
    • 천단위 수에서 컴마나 소숫점 같은 거 있으면 테스트에 제대로 안먹히더라구요🥵
    • 실제로 빌드는 되는데 테스트만 안되기도 햇져요ㅠ..ㅠ
  • 그래서 그룹 구분자, 쉼표를 제거(1,000 → 1000)로 테스트 비교 문자열을 항상 일정하게 유지하기 위해서 넣었습니다...(지금 생각해보니 여기다말고 다른데 빼는 게 이쁠 것 같네요)
    private let formatter: NumberFormatter = {
        let f = NumberFormatter()
        f.locale = Locale(identifier: "en_US_POSIX")
        f.numberStyle = .decimal
        f.usesGroupingSeparator = false
        f.maximumFractionDigits = 0
        return f
    }()

🧪 CalculatorService Unit Test

  • 사칙연산이 정상 계산되어 displayText에 올바른 결과가 나오는지만 검증
    • 더하기만 테스트코드 짯습니다 ㅎㅎ
  • GWT(Given–When–Then) 패턴으로 테스트 흐름을 명확히 구성하려 노력햇더용
  • 테스트는 UI 없이 Service 로직만 단독 실행하여 크래시 없이 안정적으로 검증되도록 설계
func test_add() {
    // Given: 테스트 대상 서비스 생성
    let sut = CalculatorService()

    // When: 2 + 3 연산 실행
    sut.inputDigit(2)
    sut.setOperation(.add)
    sut.inputDigit(3)
    sut.equals()

    // Then: 결과가 "5"로 출력되는지 확인
    XCTAssertEqual(sut.displayText, "5")
}

@dudwntjs dudwntjs self-assigned this Dec 26, 2025
Copy link
Collaborator

@Yeonnies Yeonnies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

항상 자세한 PR 감사합니다!
뷰모델, 서비스 계층을 분리하신 이유가 궁금해요!
그리고 뷰모델도 테스트 해보심 조을 거 같아요..

--편지--
언니는 진짜 해야.. 보고있으면 넘 따뜻하고 위안이 돼..
테스트코드 스터디에 와줘서 고마어.. 내가 잘 한지 잘 몰겠는데 언니가 많이 배워갔음 조켓어
솔플리에 테스트코드 리드는 꼭 언니여야해 아랏지??
항상 열심히 PR 작성해주고 노션에서도 예시 들어가면서 설명해주는 거 보면서
진짜 선생님 같다고 느꼈어.. 맨날 발표시키고 싶었어.. 최고야..


final class CalculatorServiceTests: XCTestCase {

func test_add() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

습 네이밍 아쉽다


final class CalculatorViewController: UIViewController {

private let viewModel: CalculatorViewModel
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants