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