관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] clean architecture - DI (DI패턴, unit test, business logic test) 본문

Architecture (swift)/MVVM (맛보기)

[iOS - swift] clean architecture - DI (DI패턴, unit test, business logic test)

jake-kim 2021. 7. 15. 00:02

1. DI패턴 (필요한 곳에서 protocol에 선언하는 방법)

2. 테스트 구조를 고려한 DI패턴

Usecase Test를 위한 ViewModel 구조

  • ViewModel에 Input, Output이 존재하고 특정 Input일때 mock usecase를 동작시켜서 예상되는 Output이 나오는지 확인
  • ViewModel의 Input, Output 정의
protocol AInput {
    func viewDidLoad()
}

protocol AOutput {
    var calculatedValue: Observable<Int> { get }
}

protocol AViewModel: AInput, AOutput {}
  • DefaultAViewModel 정의
final class DefaultAViewModel: AViewModel {

    var a: Int
    var b: Int
    let addUsecase: AddUsecase

    // MARK: - Output

    var calculatedValue: Observable<Int> = Observable(0)

    init(addUsecase: AddUsecase, a: Int, b: Int) {
        self.addUsecase = addUsecase
        self.a = a
        self.b = b
    }
}

// MARK: - Input

extension DefaultAViewModel {
    func viewDidLoad() {
        let resultValue = addUsecase.execute(a: a, b: b)
        calculatedValue.value = resultValue
    }
}

Unit Test 로직

  • Unit Test를 하는 이유: Input > usecase동작 > Ouput까지 진행되었을때 output이 예상하는 output과 동일함을 확인하여 논리 흐름의 사이클을 확인하기 위함
  • AddUsecaseTests 파일 생성: UnitTest 파일 추가 방법 참고
class AddUsecaseTests: XCTestCase {

}
  • Usecase Mock데이터 추가
    class MockAddUsecase: AddUsecase {
        func execute(a: Int, b: Int) -> Int {
            return a * b
        }
    }
  • test 코드 작성: given - when - then 으로 작성
    func test_whenViewDidLoadAndCalculateValue_thenValue() {
        // given
        let a = 2
        let b = 5
        let usecase = MockAddUsecase()
        let viewModel = DefaultAViewModel(addUsecase: usecase, a: a, b: b)

        // when
        viewModel.viewDidLoad()

        // then
        XCTAssertEqual(viewModel.calculatedValue.value, a * b)
    }

* source code: https://github.com/JK0369/DI_for_unittest/commit/6c3ad38d5546d15a40e7908a0f95090f6dee7b2f

Comments