Skip to content

Commit 7aa8f60

Browse files
author
Florian Rieger
authored
Merge pull request #22 from AppCron/interactor-spy
InteractorSpy
2 parents 65e494b + 1653a80 commit 7aa8f60

File tree

2 files changed

+316
-0
lines changed

2 files changed

+316
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Foundation
2+
3+
class InteractorSpy<Request: InteractorRequestProtocol>: Interactor {
4+
5+
var returnsResponses = [Request.Response]()
6+
var returnsErrors = [InteractorError]()
7+
8+
let noError = InteractorError(message: "no error")
9+
10+
private(set) var executedRequests = [Request]()
11+
12+
func execute(_ request: Request) {
13+
executedRequests.append(request)
14+
15+
if let error = returnsErrors.first {
16+
returnsErrors.remove(at: 0)
17+
18+
if error != noError {
19+
request.onError?(error)
20+
return
21+
}
22+
}
23+
24+
if let response = returnsResponses.first {
25+
returnsResponses.remove(at: 0)
26+
27+
request.onComplete?(response)
28+
return
29+
}
30+
}
31+
32+
// MARK: - Request Count
33+
34+
var lastRequest: Request? {
35+
get {
36+
return executedRequests.last
37+
}
38+
}
39+
40+
var isCalledOnce: Bool {
41+
get {
42+
return executedRequests.count == 1
43+
}
44+
}
45+
46+
var isNeverCalled: Bool {
47+
get {
48+
return executedRequests.count == 0
49+
}
50+
}
51+
52+
// MARK: - Response Helper
53+
54+
var returnsResponse: Request.Response? {
55+
get {
56+
return returnsResponses.first
57+
}
58+
set {
59+
returnsResponses.removeAll()
60+
if let response = newValue {
61+
returnsResponses.append(response)
62+
}
63+
}
64+
}
65+
66+
var returnsError: InteractorError? {
67+
get {
68+
return returnsErrors.first
69+
}
70+
set {
71+
returnsErrors.removeAll()
72+
if let error = newValue {
73+
returnsErrors.append(error)
74+
}
75+
}
76+
}
77+
78+
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
import XCTest
2+
@testable import ACInteractor
3+
4+
class InteractorSpyTests: XCTestCase {
5+
6+
class SampleRequest: InteractorRequest<SampleResponse> {}
7+
class SampleResponse {}
8+
9+
let spy = InteractorSpy<SampleRequest>()
10+
11+
let firstRequest = SampleRequest()
12+
let secondRequest = SampleRequest()
13+
14+
var firstRequestResponse: SampleResponse?
15+
var secondRequestResponse: SampleResponse?
16+
var firstRequestError: InteractorError?
17+
var secondRequestError: InteractorError?
18+
19+
let testError = InteractorError(message: "test error")
20+
21+
override func setUp() {
22+
super.setUp()
23+
24+
firstRequest.onComplete = { response in
25+
self.firstRequestResponse = response
26+
}
27+
28+
firstRequest.onError = { error in
29+
self.firstRequestError = error
30+
}
31+
32+
secondRequest.onComplete = { response in
33+
self.secondRequestResponse = response
34+
}
35+
36+
secondRequest.onError = { error in
37+
self.secondRequestError = error
38+
}
39+
}
40+
41+
// MARK: - Requests
42+
43+
func testExecutedRequests_returnsExecutedRequests() {
44+
// Arrange
45+
spy.execute(firstRequest)
46+
spy.execute(secondRequest)
47+
48+
// Act
49+
let executedRequests = spy.executedRequests
50+
51+
// Assert
52+
XCTAssertEqual(executedRequests.count, 2)
53+
XCTAssert(executedRequests.first === firstRequest)
54+
XCTAssert(executedRequests.last === secondRequest)
55+
}
56+
57+
func testLastRequest_returnsLastExecutedRequest() {
58+
// Arrange
59+
spy.execute(firstRequest)
60+
spy.execute(secondRequest)
61+
62+
// Act
63+
let lastRequest = spy.lastRequest
64+
65+
// Assert
66+
XCTAssert(lastRequest === secondRequest)
67+
}
68+
69+
// MARK: - Response
70+
71+
func testExecute_callsOnComplete_withStoredResponses() {
72+
// Arrange
73+
let firstResponse = SampleResponse()
74+
let secondResponse = SampleResponse()
75+
spy.returnsResponses = [firstResponse, secondResponse]
76+
77+
// Act
78+
spy.execute(firstRequest)
79+
spy.execute(secondRequest)
80+
81+
// Assert
82+
XCTAssert(firstRequestResponse === firstResponse)
83+
XCTAssert(secondRequestResponse === secondResponse)
84+
}
85+
86+
// MARK: - Error Handling
87+
88+
func testExecute_callsOnError_withStoredErrors() {
89+
// Arrange
90+
let firstError = InteractorError()
91+
let secondError = InteractorError()
92+
spy.returnsErrors = [firstError, secondError]
93+
94+
// Act
95+
spy.execute(firstRequest)
96+
spy.execute(secondRequest)
97+
98+
// Assert
99+
XCTAssert(firstRequestError === firstError)
100+
XCTAssert(secondRequestError === secondError)
101+
}
102+
103+
// MARK: - Mixed Responses and Errors
104+
105+
func testExecute_callsOnComplete_afterAllErrorsHaveBeenReturned() {
106+
// Arrange
107+
let firstResponse = SampleResponse()
108+
let secondResponse = SampleResponse()
109+
spy.returnsResponses = [firstResponse, secondResponse]
110+
spy.returnsErrors = [testError]
111+
112+
// Act
113+
spy.execute(firstRequest)
114+
spy.execute(secondRequest)
115+
116+
// Assert
117+
XCTAssert(firstRequestResponse == nil)
118+
XCTAssert(firstRequestError === testError)
119+
120+
XCTAssert(secondRequestResponse === firstResponse)
121+
XCTAssert(secondRequestError == nil)
122+
}
123+
124+
func testExecute_callsOnComplete_whenNoErrorConstantIsUsed() {
125+
// Arrange
126+
let firstResponse = SampleResponse()
127+
let secondResponse = SampleResponse()
128+
spy.returnsResponses = [firstResponse, secondResponse]
129+
spy.returnsErrors = [spy.noError, testError]
130+
131+
// Act
132+
spy.execute(firstRequest)
133+
spy.execute(secondRequest)
134+
135+
// Assert
136+
XCTAssert(firstRequestResponse === firstResponse)
137+
XCTAssert(firstRequestError == nil)
138+
139+
XCTAssert(secondRequestResponse == nil)
140+
XCTAssert(secondRequestError === testError)
141+
}
142+
143+
// MARK: - Request Count
144+
145+
func testIsCalledOnce_returnsTrue_whenCalledOnce() {
146+
var testData = [(executionCalls: Int, result: Bool)]()
147+
testData.append((executionCalls: 0, result: false))
148+
testData.append((executionCalls: 1, result: true))
149+
testData.append((executionCalls: 2, result: false))
150+
151+
for test in testData {
152+
// Arrange
153+
for _ in 0..<test.executionCalls {
154+
spy.execute(firstRequest)
155+
}
156+
157+
// Act
158+
let isCalledOnce = spy.isCalledOnce
159+
160+
// Assert
161+
XCTAssertEqual(isCalledOnce, test.result)
162+
}
163+
}
164+
165+
func testIsNeverCalled_returnsTrue_whenNeverCalled() {
166+
var testData = [(executionCalls: Int, result: Bool)]()
167+
testData.append((executionCalls: 0, result: true))
168+
testData.append((executionCalls: 1, result: false))
169+
170+
for test in testData {
171+
// Arrange
172+
for _ in 0..<test.executionCalls {
173+
spy.execute(firstRequest)
174+
}
175+
176+
// Act
177+
let isCalledOnce = spy.isNeverCalled
178+
179+
// Assert
180+
XCTAssertEqual(isCalledOnce, test.result)
181+
}
182+
}
183+
184+
// MARK: - Response Helper
185+
186+
func testReturnsResponse_returnsFirstStoredResponse() {
187+
// Arrange
188+
let firstResponse = SampleResponse()
189+
let secondResponse = SampleResponse()
190+
spy.returnsResponses = [firstResponse, secondResponse]
191+
192+
// Act
193+
let response = spy.returnsResponse
194+
195+
// Assert
196+
XCTAssert(response === firstResponse)
197+
}
198+
199+
func testSetReturnsResponse_storesResponse_overridesExistingOnes() {
200+
// Arange
201+
spy.returnsResponses = [SampleResponse(), SampleResponse()]
202+
let newResponse = SampleResponse()
203+
204+
// Act
205+
spy.returnsResponse = newResponse
206+
207+
// Assert
208+
XCTAssert(spy.returnsResponses.first === newResponse)
209+
XCTAssertEqual(spy.returnsResponses.count, 1)
210+
}
211+
212+
func testReturnsError_returnsFirstStoredError() {
213+
// Arange
214+
let firstError = InteractorError()
215+
let secondError = InteractorError()
216+
spy.returnsErrors = [firstError, secondError]
217+
218+
// Act
219+
let error = spy.returnsError
220+
221+
// Assert
222+
XCTAssert(error === firstError)
223+
}
224+
225+
func testSetReturnsError_storesError_overridesExistingOnes() {
226+
// Arange
227+
spy.returnsErrors = [InteractorError(), InteractorError()]
228+
let newError = InteractorError()
229+
230+
// Act
231+
spy.returnsError = newError
232+
233+
// Assert
234+
XCTAssert(spy.returnsErrors.first === newError)
235+
XCTAssertEqual(spy.returnsErrors.count, 1)
236+
}
237+
238+
}

0 commit comments

Comments
 (0)