Skip to content

Commit 8194ff3

Browse files
committed
Refactor tests for movies list view model
1 parent 30970cc commit 8194ff3

File tree

2 files changed

+80
-21
lines changed

2 files changed

+80
-21
lines changed

ExampleMVVM.xcodeproj/project.pbxproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,9 @@
398398
isa = PBXGroup;
399399
children = (
400400
1F90353F2307757D00DEA4BD /* Mocks */,
401-
1F9034D92307238C00DEA4BD /* MoviesQueriesListViewModelTests.swift */,
402401
1F9035392307716300DEA4BD /* MoviesListViewModelTests.swift */,
403402
1F90353623076B8A00DEA4BD /* MovieDetailsViewModelTests.swift */,
403+
1F9034D92307238C00DEA4BD /* MoviesQueriesListViewModelTests.swift */,
404404
);
405405
path = MoviesScene;
406406
sourceTree = "<group>";

ExampleMVVMTests/Presentation/MoviesScene/MoviesListViewModelTests.swift

+79-20
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,58 @@ class MoviesListViewModelTests: XCTestCase {
1717

1818
class SearchMoviesUseCaseMock: SearchMoviesUseCase {
1919
var executeCallCount: Int = 0
20-
var error: Error?
21-
var page = MoviesPage(page: 0, totalPages: 0, movies: [])
20+
21+
typealias ExecuteBlock = (
22+
SearchMoviesUseCaseRequestValue,
23+
(MoviesPage) -> Void,
24+
(Result<MoviesPage, Error>) -> Void
25+
) -> Void
26+
27+
lazy var _execute: ExecuteBlock = { _, _, _ in
28+
XCTFail("not implemented")
29+
}
2230

2331
func execute(
2432
requestValue: SearchMoviesUseCaseRequestValue,
2533
cached: @escaping (MoviesPage) -> Void,
2634
completion: @escaping (Result<MoviesPage, Error>) -> Void
2735
) -> Cancellable? {
28-
if let error = error {
29-
completion(.failure(error))
30-
} else {
31-
completion(.success(page))
32-
}
3336
executeCallCount += 1
37+
_execute(requestValue, cached, completion)
3438
return nil
3539
}
3640
}
3741

42+
func test_whenFetchUsersUseCaseRetrievesEmptyPage_thenViewModelIsEmpty() {
43+
// given
44+
let searchMoviesUseCaseMock = SearchMoviesUseCaseMock()
45+
46+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
47+
XCTAssertEqual(requestValue.page, 1)
48+
completion(.success(MoviesPage(page: 1, totalPages: 0, movies: [])))
49+
}
50+
let viewModel = DefaultMoviesListViewModel(
51+
searchMoviesUseCase: searchMoviesUseCaseMock,
52+
mainQueue: DispatchQueueTypeMock()
53+
)
54+
// when
55+
viewModel.didSearch(query: "query")
56+
57+
// then
58+
XCTAssertEqual(viewModel.currentPage, 1)
59+
XCTAssertFalse(viewModel.hasMorePages)
60+
XCTAssertTrue(viewModel.items.value.isEmpty)
61+
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 1)
62+
}
63+
3864
func test_whenSearchMoviesUseCaseRetrievesFirstPage_thenViewModelContainsOnlyFirstPage() {
3965
// given
4066
let searchMoviesUseCaseMock = SearchMoviesUseCaseMock()
41-
searchMoviesUseCaseMock.page = MoviesPage(page: 1, totalPages: 2, movies: moviesPages[0].movies)
67+
68+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
69+
XCTAssertEqual(requestValue.page, 1)
70+
completion(.success(self.moviesPages[0]))
71+
}
4272
let viewModel = DefaultMoviesListViewModel(
4373
searchMoviesUseCase: searchMoviesUseCaseMock,
4474
mainQueue: DispatchQueueTypeMock()
@@ -47,6 +77,10 @@ class MoviesListViewModelTests: XCTestCase {
4777
viewModel.didSearch(query: "query")
4878

4979
// then
80+
let expectedItems: [MoviesListItemViewModel] = moviesPages[0]
81+
.movies
82+
.map { MoviesListItemViewModel(movie: $0) }
83+
XCTAssertEqual(viewModel.items.value, expectedItems)
5084
XCTAssertEqual(viewModel.currentPage, 1)
5185
XCTAssertTrue(viewModel.hasMorePages)
5286
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 1)
@@ -55,59 +89,84 @@ class MoviesListViewModelTests: XCTestCase {
5589
func test_whenSearchMoviesUseCaseRetrievesFirstAndSecondPage_thenViewModelContainsTwoPages() {
5690
// given
5791
let searchMoviesUseCaseMock = SearchMoviesUseCaseMock()
58-
searchMoviesUseCaseMock.page = MoviesPage(page: 1, totalPages: 2, movies: moviesPages[0].movies)
92+
93+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
94+
XCTAssertEqual(requestValue.page, 1)
95+
completion(.success(self.moviesPages[0]))
96+
}
5997
let viewModel = DefaultMoviesListViewModel.make(
6098
searchMoviesUseCase: searchMoviesUseCaseMock
6199
)
62100
// when
63101
viewModel.didSearch(query: "query")
64102
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 1)
65103

66-
searchMoviesUseCaseMock.page = MoviesPage(page: 2, totalPages: 2, movies: moviesPages[1].movies)
67-
104+
let testPage2 = 1
105+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
106+
XCTAssertEqual(requestValue.page, 2)
107+
completion(.success(self.moviesPages[1]))
108+
}
109+
68110
viewModel.didLoadNextPage()
69-
111+
70112
// then
113+
let expectedItems: [MoviesListItemViewModel] = moviesPages
114+
.flatMap { $0.movies }
115+
.map { MoviesListItemViewModel(movie: $0) }
116+
XCTAssertEqual(viewModel.items.value, expectedItems)
71117
XCTAssertEqual(viewModel.currentPage, 2)
72118
XCTAssertFalse(viewModel.hasMorePages)
73119
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 2)
74120
}
75-
121+
76122
func test_whenSearchMoviesUseCaseReturnsError_thenViewModelContainsError() {
77123
// given
78124
let searchMoviesUseCaseMock = SearchMoviesUseCaseMock()
79-
searchMoviesUseCaseMock.error = SearchMoviesUseCaseError.someError
125+
126+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
127+
XCTAssertEqual(requestValue.page, 1)
128+
completion(.failure(SearchMoviesUseCaseError.someError))
129+
}
80130
let viewModel = DefaultMoviesListViewModel.make(
81131
searchMoviesUseCase: searchMoviesUseCaseMock
82132
)
83133
// when
84134
viewModel.didSearch(query: "query")
85-
135+
86136
// then
87137
XCTAssertNotNil(viewModel.error)
138+
XCTAssertTrue(viewModel.items.value.isEmpty)
88139
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 1)
89140
}
90-
141+
91142
func test_whenLastPage_thenHasNoPageIsTrue() {
92143
// given
93144
let searchMoviesUseCaseMock = SearchMoviesUseCaseMock()
94-
searchMoviesUseCaseMock.page = MoviesPage(page: 1, totalPages: 2, movies: moviesPages[0].movies)
145+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
146+
XCTAssertEqual(requestValue.page, 1)
147+
completion(.success(self.moviesPages[0]))
148+
}
95149
let viewModel = DefaultMoviesListViewModel.make(
96150
searchMoviesUseCase: searchMoviesUseCaseMock
97151
)
98152
// when
99153
viewModel.didSearch(query: "query")
100154
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 1)
101-
102-
searchMoviesUseCaseMock.page = MoviesPage(page: 2, totalPages: 2, movies: moviesPages[1].movies)
155+
156+
searchMoviesUseCaseMock._execute = { requestValue, _, completion in
157+
XCTAssertEqual(requestValue.page, 2)
158+
completion(.success(self.moviesPages[1]))
159+
}
103160

104161
viewModel.didLoadNextPage()
105-
162+
106163
// then
107164
XCTAssertEqual(viewModel.currentPage, 2)
108165
XCTAssertFalse(viewModel.hasMorePages)
109166
XCTAssertEqual(searchMoviesUseCaseMock.executeCallCount, 2)
110167
}
168+
169+
111170
}
112171

113172
extension DefaultMoviesListViewModel {

0 commit comments

Comments
 (0)