Skip to content

Commit 65a3e91

Browse files
authored
More readable way (#21)
* waitUntilVisible -> waitUntilViewDidLoad * Remove a code for only testing
1 parent c358214 commit 65a3e91

16 files changed

+238
-82
lines changed

TestableDesignExample.xcodeproj/project.pbxproj

Lines changed: 36 additions & 0 deletions
Large diffs are not rendered by default.

TestableDesignExample/MvcArchitecture/Stargazers/Controller/StargazersInfiniteScrollController.swift

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,36 @@ protocol StargazersInfiniteScrollControllerProtocol {}
99

1010

1111
class StargazersInfiniteScrollController: StargazersInfiniteScrollControllerProtocol {
12-
private let scrollView: UIScrollView
12+
private let injectable: RxCocoaInjectable.InjectableUIScrollView
1313
private let model: StargazersModelProtocol
1414
private let trigger: InfiniteScrollTriggerProtocol
1515
private let disposeBag = RxSwift.DisposeBag()
16-
internal var didHandle = {}
1716

1817

1918
init(
20-
watching scrollView: UIScrollView,
19+
watching injectable: RxCocoaInjectable.InjectableUIScrollView,
2120
determiningBy trigger: InfiniteScrollTriggerProtocol,
2221
notifying model: StargazersModelProtocol
2322
) {
24-
self.scrollView = scrollView
23+
self.injectable = injectable
2524
self.model = model
2625
self.trigger = trigger
2726

28-
self.scrollView.rx
27+
self.injectable
2928
.didScroll
3029
.asDriver()
3130
.drive(onNext: { [weak self] _ in
3231
guard let this = self else { return }
3332

33+
let scrollView = this.injectable.scrollView
34+
3435
if this.trigger.shouldLoadY(
35-
contentOffset: this.scrollView.contentOffset,
36-
contentSize: this.scrollView.contentSize,
37-
scrollViewSize: this.scrollView.bounds.size
36+
contentOffset: scrollView.contentOffset,
37+
contentSize: scrollView.contentSize,
38+
scrollViewSize: scrollView.bounds.size
3839
) {
3940
this.model.fetchNext()
4041
}
41-
42-
this.didHandle()
4342
})
4443
.disposed(by: self.disposeBag)
4544
}

TestableDesignExample/MvcArchitecture/Stargazers/Controller/StargazersInfiniteScrollControllerTests.swift

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,53 @@ class StargazersInfiniteScrollControllerTests: XCTestCase {
66
func testTrigger() {
77
let scrollView = self.createScrollView()
88

9-
waitUntilVisible(on: self, testing: scrollView) { fulfill in
10-
let spy = StargazersModelSpy()
9+
waitUntilViewDidLoad(on: self, testing: scrollView) {
10+
let scrollViewStub = RxCocoaInjectable.InjectableUIScrollView
11+
.createStub(of: scrollView)
12+
13+
let modelSpy = StargazersModelSpy()
1114

1215
let controller = StargazersInfiniteScrollController(
13-
watching: scrollView,
16+
watching: scrollViewStub.injectable,
1417
determiningBy: InfiniteScrollTriggerStub(
1518
firstResult: true
1619
),
17-
notifying: spy
20+
notifying: modelSpy
1821
)
1922

20-
controller.didHandle = {
21-
XCTAssertEqual(spy.callArgs.count, 1)
22-
fulfill()
23-
}
23+
scrollViewStub.scroll()
2424

25-
EventSimulator.simulateScroll(
26-
on: scrollView,
27-
to: CGPoint(x: 0, y: 200)
28-
)
25+
XCTAssertEqual(modelSpy.callArgs.count, 1)
26+
27+
// NOTE: Hold reference
28+
_ = controller
2929
}
3030
}
3131

3232

3333
func testNotTrigger() {
3434
let scrollView = self.createScrollView()
3535

36-
waitUntilVisible(on: self, testing: scrollView) { fulfill in
37-
let spy = StargazersModelSpy()
36+
waitUntilViewDidLoad(on: self, testing: scrollView) {
37+
let scrollViewStub = RxCocoaInjectable.InjectableUIScrollView
38+
.createStub(of: scrollView)
39+
40+
let modelSpy = StargazersModelSpy()
3841

3942
let controller = StargazersInfiniteScrollController(
40-
watching: scrollView,
43+
watching: scrollViewStub.injectable,
4144
determiningBy: InfiniteScrollTriggerStub(
4245
firstResult: false
4346
),
44-
notifying: spy
47+
notifying: modelSpy
4548
)
4649

47-
controller.didHandle = {
48-
XCTAssertEqual(spy.callArgs.count, 0)
49-
fulfill()
50-
}
50+
scrollViewStub.scroll()
5151

52-
EventSimulator.simulateScroll(
53-
on: scrollView,
54-
to: CGPoint(x: 0, y: 1)
55-
)
52+
XCTAssertEqual(modelSpy.callArgs.count, 0)
53+
54+
// NOTE: Hold reference
55+
_ = controller
5656
}
5757
}
5858

TestableDesignExample/MvcArchitecture/Stargazers/Controller/StargazersRefreshController.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,25 @@ protocol StargazersRefreshControllerProtocol {}
99

1010

1111
class StargazersRefreshController: StargazersRefreshControllerProtocol {
12-
private let refreshController: UIRefreshControl
12+
private let injectable: RxCocoaInjectable.InjectableUIRefreshControl
1313
private let model: StargazersModelProtocol
1414
private let disposeBag = RxSwift.DisposeBag()
15-
internal var didHandle = {}
1615

1716

1817
init(
19-
watching refreshController: UIRefreshControl,
18+
watching injectable: RxCocoaInjectable.InjectableUIRefreshControl,
2019
notifying model: StargazersModelProtocol
2120
) {
22-
self.refreshController = refreshController
21+
self.injectable = injectable
2322
self.model = model
2423

25-
self.refreshController.rx
26-
.controlEvent(.valueChanged)
24+
self.injectable.valueChanged
2725
.asDriver()
2826
.drive(onNext: { [weak self] _ in
2927
guard let this = self else { return }
3028

3129
this.model.clear()
3230
this.model.fetchNext()
33-
34-
this.didHandle()
3531
})
3632
.disposed(by: self.disposeBag)
3733
}

TestableDesignExample/MvcArchitecture/Stargazers/Controller/StargazersRefreshControllerTests.swift

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,25 @@ class StargazersRefreshControllerTests: XCTestCase {
66
func testTrigger() {
77
let scrollView = self.createScrollView()
88
let refreshControl = UIRefreshControl()
9-
109
scrollView.refreshControl = refreshControl
1110

12-
waitUntilVisible(on: self, testing: scrollView) { fulfill in
13-
let spy = StargazersModelSpy()
11+
waitUntilViewDidLoad(on: self, testing: scrollView) {
12+
let refreshControlStub = RxCocoaInjectable.InjectableUIRefreshControl
13+
.createStub(of: refreshControl)
14+
15+
let modelSpy = StargazersModelSpy()
16+
1417
let controller = StargazersRefreshController(
15-
watching: refreshControl,
16-
notifying: spy
18+
watching: refreshControlStub.injectable,
19+
notifying: modelSpy
1720
)
1821

19-
controller.didHandle = {
20-
XCTAssertEqual(spy.callArgs, [.clear, .fetchNext])
21-
fulfill()
22-
}
22+
refreshControlStub.refresh()
2323

24-
EventSimulator.simulateBeginRefreshing(on: refreshControl)
24+
XCTAssertEqual(modelSpy.callArgs, [.clear, .fetchNext])
25+
26+
// NOTE: Hold reference
27+
_ = controller
2528
}
2629
}
2730

@@ -31,4 +34,3 @@ class StargazersRefreshControllerTests: XCTestCase {
3134
return views.scrollView
3235
}
3336
}
34-

TestableDesignExample/MvcArchitecture/Stargazers/StargazersMvcComposer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ class StargazersMvcComposer: UIViewController {
5454
)
5555

5656
self.scrollController = StargazersInfiniteScrollController(
57-
watching: rootView.tableView,
57+
watching: .makeInjectable(of: rootView.tableView),
5858
determiningBy: InfiniteScrollThresholdTrigger(
5959
basedOn: PerformanceParameter.stargazersInfiniteScrollThreshold
6060
),
6161
notifying: self.model
6262
)
6363

6464
self.navigationViewMediator = StargazersNavigationViewMediator(
65-
watching: rootView.tableView,
65+
watching: .makeInjectable(of: rootView.tableView),
6666
findingVisibleRowBy: dataSource,
6767
navigatingBy: self.navigator
6868
)
@@ -81,7 +81,7 @@ class StargazersMvcComposer: UIViewController {
8181
)
8282

8383
self.refreshController = StargazersRefreshController(
84-
watching: refreshControl,
84+
watching: .makeInjectable(of: refreshControl),
8585
notifying: self.model
8686
)
8787
}

TestableDesignExample/MvcArchitecture/Stargazers/View/ViewMediator/StargazersNavigationViewMediator.swift

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,27 @@ protocol StargazersNavigationViewMediatorProtocol {}
1010

1111
class StargazersNavigationViewMediator: StargazersNavigationViewMediatorProtocol {
1212
private let navigator: NavigatorProtocol
13-
private let tableView: UITableView
13+
private let injectable: RxCocoaInjectable.InjectableUITableView
1414
private let dataSource: StargazersTableViewDataSourceProtocol
1515
private let disposeBag = RxSwift.DisposeBag()
16-
internal var didHandle = {}
1716

1817

1918
init(
20-
watching tableView: UITableView,
19+
watching injectable: RxCocoaInjectable.InjectableUITableView,
2120
findingVisibleRowBy dataSource: StargazersTableViewDataSourceProtocol,
2221
navigatingBy navigator: NavigatorProtocol
2322
) {
2423
self.navigator = navigator
25-
self.tableView = tableView
24+
self.injectable = injectable
2625
self.dataSource = dataSource
2726

28-
tableView.rx
27+
self.injectable
2928
.itemSelected
3029
.asDriver()
3130
.drive(onNext: { [weak self] indexPath in
3231
guard let this = self else { return }
3332

3433
this.navigate(by: indexPath)
35-
36-
this.didHandle()
3734
})
3835
.disposed(by: self.disposeBag)
3936
}
@@ -51,6 +48,6 @@ class StargazersNavigationViewMediator: StargazersNavigationViewMediatorProtocol
5148

5249
self.navigator.navigate(to: stargazerViewController, animated: true)
5350

54-
self.tableView.deselectRow(at: indexPath, animated: true)
51+
self.injectable.tableView.deselectRow(at: indexPath, animated: true)
5552
}
5653
}

TestableDesignExample/MvcArchitecture/Stargazers/View/ViewMediator/StargazersNavigationViewMediatorTests.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,26 @@ class StargazersNavigationViewMediatorTests: XCTestCase {
66
func testNavigate() {
77
let tableView = UITableView()
88

9-
waitUntilVisible(on: self, testing: tableView) { fulfill in
10-
let navigatorSpy = NavigatorSpy()
9+
waitUntilViewDidLoad(on: self, testing: tableView) {
10+
let tableViewStub = RxCocoaInjectable.InjectableUITableView.createStub(of: tableView)
1111
let dataSourceStub = StargazersTableViewDataSourceStub(firstResult: [
1212
GitHubUserStub.create()
1313
])
1414

15+
let navigatorSpy = NavigatorSpy()
16+
1517
let viewMediator = StargazersNavigationViewMediator(
16-
watching: tableView,
18+
watching: tableViewStub.injectable,
1719
findingVisibleRowBy: dataSourceStub,
1820
navigatingBy: navigatorSpy
1921
)
2022

21-
viewMediator.didHandle = {
22-
XCTAssertEqual(navigatorSpy.callArgs.count, 1)
23-
fulfill()
24-
}
25-
26-
EventSimulator.simulateSelect(
27-
on: tableView,
28-
at: IndexPath(
29-
row: 0,
30-
section: 0
31-
)
32-
)
23+
tableViewStub.selectItem(IndexPath(row: 0, section: 0))
24+
25+
XCTAssertEqual(navigatorSpy.callArgs.count, 1)
26+
27+
// NOTE: Hold reference
28+
_ = viewMediator
3329
}
3430
}
3531
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enum RxCocoaInjectable {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import UIKit
2+
import RxSwift
3+
import RxCocoa
4+
5+
6+
7+
extension RxCocoaInjectable {
8+
struct InjectableUIRefreshControl {
9+
let refreshControl: UIRefreshControl
10+
let valueChanged: RxCocoa.ControlEvent<Void>
11+
12+
13+
static func makeInjectable(
14+
of refreshControl: UIRefreshControl
15+
) -> InjectableUIRefreshControl {
16+
return InjectableUIRefreshControl(
17+
refreshControl: refreshControl,
18+
valueChanged: refreshControl.rx.controlEvent(.valueChanged)
19+
)
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)