본문 바로가기
Swift

TCA를 활용한 계산기 앱 및 테스트 코드 작성하기

by mr.conan 2023. 7. 25.
728x90
반응형

모델과 액션 정의

TCA의 기본 구성 요소인 상태(State)와 액션(Action)을 정의합니다.

import Foundation

enum CalculatorAction {
    case digitTapped(String)
    case clearTapped
    case equalTapped
    case operatorTapped(String)
}

struct CalculatorState: Equatable {
    var display: String = "0"
    var result: Double? = nil
    var operatorSymbol: String? = nil
}

 

 

리듀서 정의

앱의 상태(State)와 액션(Action)을 기반으로 리듀서를 정의합니다.

import ComposableArchitecture

let calculatorReducer = Reducer<CalculatorState, CalculatorAction, Void> { state, action, _ in
    switch action {
    case let .digitTapped(digit):
        if state.display == "0" {
            state.display = digit
        } else {
            state.display.append(digit)
        }
        return .none

    case .clearTapped:
        state = CalculatorState()
        return .none

    case .equalTapped:
        state.result = Double(state.display)
        return .none

    case let .operatorTapped(operatorSymbol):
        state.result = Double(state.display)
        state.operatorSymbol = operatorSymbol
        state.display = "0"
        return .none
    }
}

 

 

뷰 구현

SwiftUI를 사용하여 계산기 앱의 뷰를 구현합니다.

import SwiftUI
import ComposableArchitecture

struct CalculatorView: View {
    let store: Store<CalculatorState, CalculatorAction>

    var body: some View {
        WithViewStore(self.store) { viewStore in
            VStack(spacing: 20) {
                Text(viewStore.display)
                    .font(.system(size: 36))
                    .padding()

                HStack(spacing: 20) {
                    // 숫자 버튼 1부터 9까지 추가
                    CalculatorButton("1", action: { viewStore.send(.digitTapped("1")) })
                    CalculatorButton("2", action: { viewStore.send(.digitTapped("2")) })
                    CalculatorButton("3", action: { viewStore.send(.digitTapped("3")) })
                    CalculatorButton("4", action: { viewStore.send(.digitTapped("4")) })
                    CalculatorButton("5", action: { viewStore.send(.digitTapped("5")) })
                    CalculatorButton("6", action: { viewStore.send(.digitTapped("6")) })
                    CalculatorButton("7", action: { viewStore.send(.digitTapped("7")) })
                    CalculatorButton("8", action: { viewStore.send(.digitTapped("8")) })
                    CalculatorButton("9", action: { viewStore.send(.digitTapped("9")) })
                    CalculatorButton("0", action: { viewStore.send(.digitTapped("0")) })
                    // 더하기, 빼기, 나누기, 곱하기 버튼 추가
                    CalculatorButton("+", action: { viewStore.send(.operatorTapped("+")) })
                    CalculatorButton("-", action: { viewStore.send(.operatorTapped("-")) })
                    CalculatorButton("×", action: { viewStore.send(.operatorTapped("×")) })
                    CalculatorButton("÷", action: { viewStore.send(.operatorTapped("÷")) })
                }

                HStack(spacing: 20) {
                    CalculatorButton("C", action: { viewStore.send(.clearTapped) })
                    CalculatorButton("=", action: { viewStore.send(.equalTapped) })
                }
            }
            .padding()
        }
    }
}

 

 

뷰와 리듀서 연결

TCA의 Store와 뷰를 연결하여 앱을 구성합니다.

import SwiftUI
import ComposableArchitecture

@main
struct CalculatorApp: App {
    var body: some Scene {
        WindowGroup {
            CalculatorView(
                store: Store(
                    initialState: CalculatorState(),
                    reducer: calculatorReducer,
                    environment: ()
                )
            )
        }
    }
}

 

 

테스트 코드 작성

TCA의 TestStore를 사용하여 계산기 앱의 기능을 테스트하는 테스트 코드를 작성합니다.

import XCTest
import ComposableArchitecture
@testable import YourProjectName

class CalculatorTests: XCTestCase {

    func testTypingDigits() {
        let store = TestStore(
            initialState: CalculatorState(),
            reducer: calculatorReducer,
            environment: ()
        )

        store.send(.digitTapped("1"))
        store.send(.digitTapped("2"))
        store.send(.digitTapped("3"))

        store.assert(
            .send(.digitTapped("4")) {
                $0.display = "1234"
            },
            .send(.digitTapped("5")) {
                $0.display = "12345"
            }
        )
    }

    func testClearButton() {
        let store = TestStore(
            initialState: CalculatorState(display: "1234"),
            reducer: calculatorReducer,
            environment: ()
        )

        store.send(.clearTapped)

        store.assert(
            .send(.clearTapped) {
                $0.display = "0"
                $0.result = nil
                $0.operatorSymbol = nil
            }
        )
    }

    // 더하기, 빼기, 나누기, 곱하기 테스트 케이스 추가
    func testArithmeticOperations() {
        let store = TestStore(
            initialState: CalculatorState(),
            reducer: calculatorReducer,
            environment: ()
        )

        store.send(.digitTapped("1"))
        store.send(.operatorTapped("+"))
        store.send(.digitTapped("2"))
        store.send(.equalTapped)

        store.assert(
            .send(.digitTapped("3")) {
                $0.display = "3"
            }
        )

        store.send(.operatorTapped("-"))
        store.send(.digitTapped("1"))
        store.send(.equalTapped)

        store.assert(
            .send(.digitTapped("2")) {
                $0.display = "2"
            }
        )

        // 나누기, 곱하기도 테스트 진행
    }
}

 

위와 같이 뷰와 테스트 코드를 작성하여 계산기 앱에서 더하기, 빼기, 나누기, 곱하기 연산이 잘 동작하는지 테스트할 수 있습니다. 이제 앱을 실행하고 계산을 수행해보면 더하기, 빼기, 나누기, 곱하기가 올바르게 동작하는 것을 확인하실 수 있을 것입니다. 또한, 테스트 코드를 실행하여 각 연산에 대한 테스트가 올바르게 수행되는지 확인해보세요. 성공적으로 동작하고 테스트가 통과된 계산기 앱을 완성하였습니다! 😊

728x90
반응형