From 2c975d1ea4c00ed7696c7d44eeffafd575acaab1 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 19:02:22 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[feat]=20QuestView=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Home/View/QuestView.swift | 16 +++++---- .../Mocks/QuestRepositoryMock.swift | 0 .../Presentation/Mocks/QuestUseCaseMock.swift | 8 +++++ .../ViewModel/QuestViewModelTests.swift | 35 +++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) rename DailyQuest/DailyQuestTests/Domain/{UseCases => }/Mocks/QuestRepositoryMock.swift (100%) create mode 100644 DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift create mode 100644 DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift diff --git a/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift b/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift index e8700d9..7c36e45 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift @@ -33,13 +33,15 @@ final class QuestView: UITableView { } private func bind() { -// viewModel -// .data -// .bind(to: rx.items(cellIdentifier: QuestCell.reuseIdentifier, cellType: QuestCell.self)) { row, item, cell in -// cell.setup(with: item) -// cell.backgroundColor = .white -// } -// .disposed(by: disposableBag) + let output = viewModel.transform(input: QuestViewModel.Input(viewDidLoad: .just(Date()).asObservable()), disposeBag: disposableBag) + + output + .data + .bind(to: rx.items(cellIdentifier: QuestCell.reuseIdentifier, cellType: QuestCell.self)) { row, item, cell in + cell.setup(with: item) + cell.backgroundColor = .white + } + .disposed(by: disposableBag) } } diff --git a/DailyQuest/DailyQuestTests/Domain/UseCases/Mocks/QuestRepositoryMock.swift b/DailyQuest/DailyQuestTests/Domain/Mocks/QuestRepositoryMock.swift similarity index 100% rename from DailyQuest/DailyQuestTests/Domain/UseCases/Mocks/QuestRepositoryMock.swift rename to DailyQuest/DailyQuestTests/Domain/Mocks/QuestRepositoryMock.swift diff --git a/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift b/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift new file mode 100644 index 0000000..80d2ec9 --- /dev/null +++ b/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift @@ -0,0 +1,8 @@ +// +// QuestUseCaseMock.swift +// DailyQuestTests +// +// Created by jinwoong Kim on 2022/11/21. +// + +import Foundation diff --git a/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift new file mode 100644 index 0000000..ea7c269 --- /dev/null +++ b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift @@ -0,0 +1,35 @@ +// +// QuestViewModelTests.swift +// DailyQuestTests +// +// Created by jinwoong Kim on 2022/11/21. +// + +import XCTest + +final class QuestViewModelTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} From 8efb04b06b21e9311bbcede17cc2a47cc5c3c852 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 19:02:36 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[feat]=20QuestViewModel=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/ViewModel/QuestViewModel.swift | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift index b7e566d..449bfa5 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift @@ -8,18 +8,32 @@ import Foundation import RxSwift +import RxCocoa final class QuestViewModel { private let questUseCase: QuestUseCase - -// let quests = [ -// Quest(groupId: UUID(), uuid: UUID(), title: "물마시기", currentCount: 4, totalCount: 5), -// Quest(groupId: UUID(), uuid: UUID(), title: "책읽기", currentCount: 9, totalCount: 20), -// Quest(groupId: UUID(), uuid: UUID(), title: "달리기", currentCount: 4, totalCount: 9), -// Quest(groupId: UUID(), uuid: UUID(), title: "잠자기", currentCount: 1, totalCount: 1) -// ] - + init(questUseCase: QuestUseCase) { self.questUseCase = questUseCase } + + struct Input { + let viewDidLoad: Observable + } + + struct Output { + let data = PublishSubject<[Quest]>() + } + + func transform(input: Input, disposeBag: DisposeBag) -> Output { + let output = Output() + + input + .viewDidLoad + .flatMap(questUseCase.fetch(by:)) + .bind(to: output.data) + .disposed(by: disposeBag) + + return output + } } From ab78e978bf18b14c945cc501cf3c5bfd4701e418 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 19:02:54 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[test]=20QuestUseCase=20Mock=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Mocks/QuestUseCaseMock.swift | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift b/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift index 80d2ec9..ccf3f66 100644 --- a/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift +++ b/DailyQuest/DailyQuestTests/Presentation/Mocks/QuestUseCaseMock.swift @@ -6,3 +6,24 @@ // import Foundation + +import RxSwift + +final class QuestUseCaseMock: QuestUseCase { + let quests = [ + Quest.stub(groupId: UUID(), + uuid: UUID(), + title: "물마시기", + currentCount: 0, + totalCount: 10), + Quest.stub(groupId: UUID(), + uuid: UUID(), + title: "물마시기", + currentCount: 0, + totalCount: 10), + ] + + func fetch(by date: Date) -> Observable<[Quest]> { + return Observable.just(quests) + } +} From 2825a40553696fae77a7e0dd8c1bb46aff5ea64a Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 19:03:28 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[test]=20QuestViewModel=20test=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RxCocoa.runtime이 없다는 에러가 발생함. --- .../ViewModel/QuestViewModelTests.swift | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift index ea7c269..b83813e 100644 --- a/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift +++ b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift @@ -7,7 +7,12 @@ import XCTest +import RxSwift + final class QuestViewModelTests: XCTestCase { + private var questViewModel: QuestViewModel! + private var questUseCase: QuestUseCase! + private var disposeBag = DisposeBag() override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. @@ -15,14 +20,34 @@ final class QuestViewModelTests: XCTestCase { override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. + questViewModel = nil + questUseCase = nil + disposeBag = .init() } - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + func testQuestViewModel_WhenUseCaseSendCorrectQuests_ThenExpectationWillBeFulfilledWithSuccess() { + // given + questUseCase = QuestUseCaseMock() + + questViewModel = QuestViewModel(questUseCase: questUseCase) + + let expectation = XCTestExpectation(description: "test success") + + // when + let output = questViewModel.transform(input: QuestViewModel.Input(viewDidLoad: .just(Date())), disposeBag: disposeBag) + + // then + output + .data + .subscribe(onNext: { data in + print(data) + expectation.fulfill() + }, onError: { _ in + XCTFail("test failed") + }) + .disposed(by: disposeBag) + + wait(for: [expectation], timeout: 1) } func testPerformanceExample() throws { From 6bac172625afe0b5b5d4ab84939fe49917302514 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 19:03:43 +0900 Subject: [PATCH 5/9] [chore] pbx --- .../DailyQuest.xcodeproj/project.pbxproj | 100 +++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 41096c9..7b35c49 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 340FDFD3292B5CE300C4E3DC /* QuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CAE317292B19A3007653AD /* QuestsRepository.swift */; }; 340FDFD4292B5DA100C4E3DC /* QuestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3416FC87292B54DB00B504C5 /* QuestUseCase.swift */; }; 340FDFD5292B5DB700C4E3DC /* DefaultQuestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3416FC89292B560800B504C5 /* DefaultQuestUseCase.swift */; }; + 340FDFDB292B7A1500C4E3DC /* QuestViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340FDFDA292B7A1500C4E3DC /* QuestViewModelTests.swift */; }; + 340FDFDE292B7A2C00C4E3DC /* QuestUseCaseMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340FDFDD292B7A2C00C4E3DC /* QuestUseCaseMock.swift */; }; 34131397291E47D300E607E1 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34131396291E47D300E607E1 /* RxCocoa */; }; 34131399291E47D300E607E1 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 34131398291E47D300E607E1 /* RxSwift */; }; 3413139C291E480500E607E1 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3413139B291E480500E607E1 /* SnapKit */; }; @@ -59,6 +61,13 @@ 34CAE318292B19A3007653AD /* QuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CAE317292B19A3007653AD /* QuestsRepository.swift */; }; 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; }; 34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FF6C2F292B8014002AFD4D /* RxBlocking-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C34292B8014002AFD4D /* RxCocoa-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C39292B8014002AFD4D /* RxRelay-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C3E292B8014002AFD4D /* RxSwift-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C43292B8014002AFD4D /* RxTest-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C48292B8014002AFD4D /* SnapKit-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 34FF6C4D292B8027002AFD4D /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; A51189C329226E66008A9D33 /* UserQuestEntity+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51189C229226E66008A9D33 /* UserQuestEntity+Mapping.swift */; }; A51F01C82923392F0031ECA2 /* UserInfoStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F01C72923392F0031ECA2 /* UserInfoStorage.swift */; }; A51F01CA2923397E0031ECA2 /* UserInfoEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F01C92923397E0031ECA2 /* UserInfoEntity.swift */; }; @@ -95,7 +104,28 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 34FF6C2E292B8014002AFD4D /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 34FF6C3E292B8014002AFD4D /* RxSwift-Dynamic in Embed Frameworks */, + 34FF6C34292B8014002AFD4D /* RxCocoa-Dynamic in Embed Frameworks */, + 34FF6C2F292B8014002AFD4D /* RxBlocking-Dynamic in Embed Frameworks */, + 34FF6C43292B8014002AFD4D /* RxTest-Dynamic in Embed Frameworks */, + 34FF6C39292B8014002AFD4D /* RxRelay-Dynamic in Embed Frameworks */, + 34FF6C48292B8014002AFD4D /* SnapKit-Dynamic in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ + 340FDFDA292B7A1500C4E3DC /* QuestViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestViewModelTests.swift; sourceTree = ""; }; + 340FDFDD292B7A2C00C4E3DC /* QuestUseCaseMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestUseCaseMock.swift; sourceTree = ""; }; 3416FC87292B54DB00B504C5 /* QuestUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestUseCase.swift; sourceTree = ""; }; 3416FC89292B560800B504C5 /* DefaultQuestUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultQuestUseCase.swift; sourceTree = ""; }; 3416FC8D292B593C00B504C5 /* Quest+Stub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Quest+Stub.swift"; sourceTree = ""; }; @@ -195,10 +225,28 @@ 340FDFD8292B61C200C4E3DC /* Presentation */ = { isa = PBXGroup; children = ( + 340FDFDC292B7A1A00C4E3DC /* Mocks */, + 340FDFD9292B7A0200C4E3DC /* ViewModel */, ); path = Presentation; sourceTree = ""; }; + 340FDFD9292B7A0200C4E3DC /* ViewModel */ = { + isa = PBXGroup; + children = ( + 340FDFDA292B7A1500C4E3DC /* QuestViewModelTests.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; + 340FDFDC292B7A1A00C4E3DC /* Mocks */ = { + isa = PBXGroup; + children = ( + 340FDFDD292B7A2C00C4E3DC /* QuestUseCaseMock.swift */, + ); + path = Mocks; + sourceTree = ""; + }; 3416FC85292B549900B504C5 /* Home */ = { isa = PBXGroup; children = ( @@ -219,6 +267,7 @@ 3416FC8B292B58F600B504C5 /* Domain */ = { isa = PBXGroup; children = ( + 3416FC91292B59C700B504C5 /* Mocks */, 3416FC90292B59BB00B504C5 /* UseCases */, ); path = Domain; @@ -236,7 +285,6 @@ isa = PBXGroup; children = ( 3416FC94292B5AD600B504C5 /* QuestUseCaseTests.swift */, - 3416FC91292B59C700B504C5 /* Mocks */, ); path = UseCases; sourceTree = ""; @@ -428,6 +476,7 @@ 34ACC342291DE9C100741371 /* DailyQuestTests */, 34ACC34C291DE9C100741371 /* DailyQuestUITests */, 34ACC32A291DE9C000741371 /* Products */, + 34FF6BF3292B7FF7002AFD4D /* Frameworks */, ); sourceTree = ""; }; @@ -528,6 +577,13 @@ path = View; sourceTree = ""; }; + 34FF6BF3292B7FF7002AFD4D /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; A51189C029226DF7008A9D33 /* RealmStorage */ = { isa = PBXGroup; children = ( @@ -688,6 +744,7 @@ 34ACC33B291DE9C100741371 /* Sources */, 34ACC33C291DE9C100741371 /* Frameworks */, 34ACC33D291DE9C100741371 /* Resources */, + 34FF6C2E292B8014002AFD4D /* Embed Frameworks */, ); buildRules = ( ); @@ -695,6 +752,14 @@ 34ACC341291DE9C100741371 /* PBXTargetDependency */, ); name = DailyQuestTests; + packageProductDependencies = ( + 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */, + 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */, + 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */, + 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */, + 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */, + 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */, + ); productName = DailyQuestTests; productReference = 34ACC33F291DE9C100741371 /* DailyQuestTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -859,6 +924,9 @@ 3416FC8E292B593C00B504C5 /* Quest+Stub.swift in Sources */, 340FDFD5292B5DB700C4E3DC /* DefaultQuestUseCase.swift in Sources */, 3416FC93292B59D300B504C5 /* QuestRepositoryMock.swift in Sources */, + 340FDFDE292B7A2C00C4E3DC /* QuestUseCaseMock.swift in Sources */, + 340FDFDB292B7A1500C4E3DC /* QuestViewModelTests.swift in Sources */, + 34FF6C4D292B8027002AFD4D /* QuestViewModel.swift in Sources */, 340FDFD4292B5DA100C4E3DC /* QuestUseCase.swift in Sources */, 340FDFD3292B5CE300C4E3DC /* QuestsRepository.swift in Sources */, ); @@ -1250,6 +1318,36 @@ package = 34ACC35E291DEF6100741371 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseStorage; }; + 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxBlocking-Dynamic"; + }; + 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxCocoa-Dynamic"; + }; + 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxRelay-Dynamic"; + }; + 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxSwift-Dynamic"; + }; + 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxTest-Dynamic"; + }; + 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = "SnapKit-Dynamic"; + }; A5AC96DE292239CA003B7637 /* RealmSwift */ = { isa = XCSwiftPackageProductDependency; package = A5AC96DD292239CA003B7637 /* XCRemoteSwiftPackageReference "realm-swift" */; From 123b50a139a97a944b1911373af979d01daeab90 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 20:21:14 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[refactor]=20Output=EC=9D=84=20subject?= =?UTF-8?q?=EC=97=90=EC=84=9C=20driver=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/Home/ViewModel/QuestViewModel.swift | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift index 449bfa5..97fcdb5 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/ViewModel/QuestViewModel.swift @@ -22,18 +22,16 @@ final class QuestViewModel { } struct Output { - let data = PublishSubject<[Quest]>() + let data: Driver<[Quest]> } func transform(input: Input, disposeBag: DisposeBag) -> Output { - let output = Output() - input + let data = input .viewDidLoad .flatMap(questUseCase.fetch(by:)) - .bind(to: output.data) - .disposed(by: disposeBag) + .asDriver(onErrorJustReturn: []) - return output + return Output(data: data) } } From 11abfed28f9b130c8378a3d8951996e679beb5d6 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 20:21:46 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[refactor]=20view=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B0=94=EC=9D=B8=EB=94=A9=20=EB=B0=A9=EC=8B=9D=EC=9D=84=20bin?= =?UTF-8?q?d=EC=97=90=EC=84=9C=20drive=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift b/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift index 7c36e45..d1d1d55 100644 --- a/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift +++ b/DailyQuest/DailyQuest/Presentation/Home/View/QuestView.swift @@ -37,7 +37,7 @@ final class QuestView: UITableView { output .data - .bind(to: rx.items(cellIdentifier: QuestCell.reuseIdentifier, cellType: QuestCell.self)) { row, item, cell in + .drive(rx.items(cellIdentifier: QuestCell.reuseIdentifier, cellType: QuestCell.self)) { row, item, cell in cell.setup(with: item) cell.backgroundColor = .white } From c2092433ff71200b983f3a013d2058f6a4cfdcfb Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 20:22:01 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[test]=20QuestViewModel=20test=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/ViewModel/QuestViewModelTests.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift index b83813e..9ec6b78 100644 --- a/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift +++ b/DailyQuest/DailyQuestTests/Presentation/ViewModel/QuestViewModelTests.swift @@ -34,16 +34,14 @@ final class QuestViewModelTests: XCTestCase { let expectation = XCTestExpectation(description: "test success") // when - let output = questViewModel.transform(input: QuestViewModel.Input(viewDidLoad: .just(Date())), disposeBag: disposeBag) + let output = questViewModel.transform(input: QuestViewModel.Input(viewDidLoad: .just(Date()).asObservable()), disposeBag: disposeBag) // then output .data - .subscribe(onNext: { data in - print(data) + .drive(onNext: { quests in + print(quests) expectation.fulfill() - }, onError: { _ in - XCTFail("test failed") }) .disposed(by: disposeBag) From ea3b7cb19e606902134371541cdb900afa406bc9 Mon Sep 17 00:00:00 2001 From: jjinwoong Date: Mon, 21 Nov 2022 20:22:12 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[chore]=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EC=9E=AC=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DailyQuest.xcodeproj/project.pbxproj | 100 ++++++------------ .../xcshareddata/swiftpm/Package.resolved | 4 +- 2 files changed, 36 insertions(+), 68 deletions(-) diff --git a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj index 7b35c49..01e35c5 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.pbxproj +++ b/DailyQuest/DailyQuest.xcodeproj/project.pbxproj @@ -12,8 +12,6 @@ 340FDFD5292B5DB700C4E3DC /* DefaultQuestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3416FC89292B560800B504C5 /* DefaultQuestUseCase.swift */; }; 340FDFDB292B7A1500C4E3DC /* QuestViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340FDFDA292B7A1500C4E3DC /* QuestViewModelTests.swift */; }; 340FDFDE292B7A2C00C4E3DC /* QuestUseCaseMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340FDFDD292B7A2C00C4E3DC /* QuestUseCaseMock.swift */; }; - 34131397291E47D300E607E1 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34131396291E47D300E607E1 /* RxCocoa */; }; - 34131399291E47D300E607E1 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 34131398291E47D300E607E1 /* RxSwift */; }; 3413139C291E480500E607E1 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3413139B291E480500E607E1 /* SnapKit */; }; 3416FC88292B54DB00B504C5 /* QuestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3416FC87292B54DB00B504C5 /* QuestUseCase.swift */; }; 3416FC8A292B560800B504C5 /* DefaultQuestUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3416FC89292B560800B504C5 /* DefaultQuestUseCase.swift */; }; @@ -61,13 +59,11 @@ 34CAE318292B19A3007653AD /* QuestsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CAE317292B19A3007653AD /* QuestsRepository.swift */; }; 34EE6EB72924C674005AF583 /* QuestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB62924C674005AF583 /* QuestView.swift */; }; 34EE6EB92924CAA1005AF583 /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; - 34FF6C2F292B8014002AFD4D /* RxBlocking-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C34292B8014002AFD4D /* RxCocoa-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C39292B8014002AFD4D /* RxRelay-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C3E292B8014002AFD4D /* RxSwift-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C43292B8014002AFD4D /* RxTest-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C48292B8014002AFD4D /* SnapKit-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 34FF6C4D292B8027002AFD4D /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */; }; + 34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5C292B8B27002AFD4D /* RxCocoa */; }; + 34FF6C5F292B8B27002AFD4D /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C5E292B8B27002AFD4D /* RxSwift */; }; + 34FF6C60292B8BC9002AFD4D /* QuestViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE6EB82924CAA1005AF583 /* QuestViewModel.swift */; }; + 34FF6C64292B8C26002AFD4D /* RxCocoa-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 34FF6C63292B8C26002AFD4D /* RxCocoa-Dynamic */; }; A51189C329226E66008A9D33 /* UserQuestEntity+Mapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51189C229226E66008A9D33 /* UserQuestEntity+Mapping.swift */; }; A51F01C82923392F0031ECA2 /* UserInfoStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F01C72923392F0031ECA2 /* UserInfoStorage.swift */; }; A51F01CA2923397E0031ECA2 /* UserInfoEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51F01C92923397E0031ECA2 /* UserInfoEntity.swift */; }; @@ -111,12 +107,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 34FF6C3E292B8014002AFD4D /* RxSwift-Dynamic in Embed Frameworks */, - 34FF6C34292B8014002AFD4D /* RxCocoa-Dynamic in Embed Frameworks */, - 34FF6C2F292B8014002AFD4D /* RxBlocking-Dynamic in Embed Frameworks */, - 34FF6C43292B8014002AFD4D /* RxTest-Dynamic in Embed Frameworks */, - 34FF6C39292B8014002AFD4D /* RxRelay-Dynamic in Embed Frameworks */, - 34FF6C48292B8014002AFD4D /* SnapKit-Dynamic in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -195,12 +185,12 @@ buildActionMask = 2147483647; files = ( A5AC96DF292239CA003B7637 /* RealmSwift in Frameworks */, - 34131399291E47D300E607E1 /* RxSwift in Frameworks */, 34ACC362291DEF6100741371 /* FirebaseDatabase in Frameworks */, 34ACC366291DEF6100741371 /* FirebaseStorage in Frameworks */, + 34FF6C5D292B8B27002AFD4D /* RxCocoa in Frameworks */, 3413139C291E480500E607E1 /* SnapKit in Frameworks */, - 34131397291E47D300E607E1 /* RxCocoa in Frameworks */, 34ACC360291DEF6100741371 /* FirebaseAuth in Frameworks */, + 34FF6C5F292B8B27002AFD4D /* RxSwift in Frameworks */, 34ACC364291DEF6100741371 /* FirebaseFirestore in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -209,6 +199,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 34FF6C64292B8C26002AFD4D /* RxCocoa-Dynamic in Frameworks */, + 34FF6C5A292B86F8002AFD4D /* SnapKit-Dynamic in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -728,10 +720,10 @@ 34ACC361291DEF6100741371 /* FirebaseDatabase */, 34ACC363291DEF6100741371 /* FirebaseFirestore */, 34ACC365291DEF6100741371 /* FirebaseStorage */, - 34131396291E47D300E607E1 /* RxCocoa */, - 34131398291E47D300E607E1 /* RxSwift */, 3413139B291E480500E607E1 /* SnapKit */, A5AC96DE292239CA003B7637 /* RealmSwift */, + 34FF6C5C292B8B27002AFD4D /* RxCocoa */, + 34FF6C5E292B8B27002AFD4D /* RxSwift */, ); productName = DailyQuest; productReference = 34ACC329291DE9C000741371 /* DailyQuest.app */; @@ -753,12 +745,8 @@ ); name = DailyQuestTests; packageProductDependencies = ( - 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */, - 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */, - 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */, - 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */, - 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */, 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */, + 34FF6C63292B8C26002AFD4D /* RxCocoa-Dynamic */, ); productName = DailyQuestTests; productReference = 34ACC33F291DE9C100741371 /* DailyQuestTests.xctest */; @@ -816,9 +804,9 @@ mainGroup = 34ACC320291DE9C000741371; packageReferences = ( 34ACC35E291DEF6100741371 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */, 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */, A5AC96DD292239CA003B7637 /* XCRemoteSwiftPackageReference "realm-swift" */, + 34FF6C5B292B8B27002AFD4D /* XCRemoteSwiftPackageReference "RxSwift" */, ); productRefGroup = 34ACC32A291DE9C000741371 /* Products */; projectDirPath = ""; @@ -926,7 +914,7 @@ 3416FC93292B59D300B504C5 /* QuestRepositoryMock.swift in Sources */, 340FDFDE292B7A2C00C4E3DC /* QuestUseCaseMock.swift in Sources */, 340FDFDB292B7A1500C4E3DC /* QuestViewModelTests.swift in Sources */, - 34FF6C4D292B8027002AFD4D /* QuestViewModel.swift in Sources */, + 34FF6C60292B8BC9002AFD4D /* QuestViewModel.swift in Sources */, 340FDFD4292B5DA100C4E3DC /* QuestUseCase.swift in Sources */, 340FDFD3292B5CE300C4E3DC /* QuestsRepository.swift in Sources */, ); @@ -1248,14 +1236,6 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.0.0; - }; - }; 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SnapKit/SnapKit"; @@ -1272,6 +1252,14 @@ kind = branch; }; }; + 34FF6C5B292B8B27002AFD4D /* XCRemoteSwiftPackageReference "RxSwift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/ReactiveX/RxSwift"; + requirement = { + branch = main; + kind = branch; + }; + }; A5AC96DD292239CA003B7637 /* XCRemoteSwiftPackageReference "realm-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/realm/realm-swift"; @@ -1283,16 +1271,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 34131396291E47D300E607E1 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 34131398291E47D300E607E1 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; 3413139B291E480500E607E1 /* SnapKit */ = { isa = XCSwiftPackageProductDependency; package = 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */; @@ -1318,35 +1296,25 @@ package = 34ACC35E291DEF6100741371 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseStorage; }; - 34FF6C2C292B8014002AFD4D /* RxBlocking-Dynamic */ = { - isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = "RxBlocking-Dynamic"; - }; - 34FF6C32292B8014002AFD4D /* RxCocoa-Dynamic */ = { - isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = "RxCocoa-Dynamic"; - }; - 34FF6C37292B8014002AFD4D /* RxRelay-Dynamic */ = { + 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */ = { isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = "RxRelay-Dynamic"; + package = 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = "SnapKit-Dynamic"; }; - 34FF6C3C292B8014002AFD4D /* RxSwift-Dynamic */ = { + 34FF6C5C292B8B27002AFD4D /* RxCocoa */ = { isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = "RxSwift-Dynamic"; + package = 34FF6C5B292B8B27002AFD4D /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = RxCocoa; }; - 34FF6C41292B8014002AFD4D /* RxTest-Dynamic */ = { + 34FF6C5E292B8B27002AFD4D /* RxSwift */ = { isa = XCSwiftPackageProductDependency; - package = 34131395291E47D300E607E1 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = "RxTest-Dynamic"; + package = 34FF6C5B292B8B27002AFD4D /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = RxSwift; }; - 34FF6C46292B8014002AFD4D /* SnapKit-Dynamic */ = { + 34FF6C63292B8C26002AFD4D /* RxCocoa-Dynamic */ = { isa = XCSwiftPackageProductDependency; - package = 3413139A291E480500E607E1 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = "SnapKit-Dynamic"; + package = 34FF6C5B292B8B27002AFD4D /* XCRemoteSwiftPackageReference "RxSwift" */; + productName = "RxCocoa-Dynamic"; }; A5AC96DE292239CA003B7637 /* RealmSwift */ = { isa = XCSwiftPackageProductDependency; diff --git a/DailyQuest/DailyQuest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DailyQuest/DailyQuest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0db98ab..f34a881 100644 --- a/DailyQuest/DailyQuest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DailyQuest/DailyQuest.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ReactiveX/RxSwift", "state" : { - "revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8", - "version" : "6.5.0" + "branch" : "main", + "revision" : "8ec08deca8271516f673706e78fb954797cd6627" } }, {