diff --git a/solutions/devsprint-brq-testes-ios-1/FinanceApp.xcodeproj/project.pbxproj b/solutions/devsprint-brq-testes-ios-1/FinanceApp.xcodeproj/project.pbxproj index 12242aca..e78bd170 100644 --- a/solutions/devsprint-brq-testes-ios-1/FinanceApp.xcodeproj/project.pbxproj +++ b/solutions/devsprint-brq-testes-ios-1/FinanceApp.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 33A58977292A7FE500E83449 /* NetworkClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33A58976292A7FE500E83449 /* NetworkClientTests.swift */; }; 4FE21AB929196913003C8ADA /* AccountTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE21AB829196913003C8ADA /* AccountTests.swift */; }; 4FE21ABC29196968003C8ADA /* DispatchQueueSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE21ABB29196968003C8ADA /* DispatchQueueSpy.swift */; }; 4FE21ABE29196989003C8ADA /* NetworkClientSpy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE21ABD29196989003C8ADA /* NetworkClientSpy.swift */; }; @@ -78,6 +79,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 33A58976292A7FE500E83449 /* NetworkClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkClientTests.swift; sourceTree = ""; }; 4FE21AB829196913003C8ADA /* AccountTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountTests.swift; sourceTree = ""; }; 4FE21ABB29196968003C8ADA /* DispatchQueueSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchQueueSpy.swift; sourceTree = ""; }; 4FE21ABD29196989003C8ADA /* NetworkClientSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkClientSpy.swift; sourceTree = ""; }; @@ -219,6 +221,7 @@ 4FE21AC3291969CE003C8ADA /* ContactListViewTests.swift */, 4FE21AC1291969BF003C8ADA /* ActivityListViewTests.swift */, 988BA51428D0EF820078896C /* HomeViewModelTests.swift */, + 33A58976292A7FE500E83449 /* NetworkClientTests.swift */, ); path = FinanceAppTests; sourceTree = ""; @@ -546,6 +549,7 @@ 988BA51528D0EF820078896C /* HomeViewModelTests.swift in Sources */, 988BA51328D0EF760078896C /* ActivityDetailsViewModelTests.swift in Sources */, 988BA50F28D0EF030078896C /* HomeDataTests.swift in Sources */, + 33A58977292A7FE500E83449 /* NetworkClientTests.swift in Sources */, 988BA51128D0EF330078896C /* FinanceServiceTests.swift in Sources */, 4FE21AB929196913003C8ADA /* AccountTests.swift in Sources */, 988BA50B28D0EE740078896C /* UITableViewCellExtensionsTests.swift in Sources */, diff --git a/solutions/devsprint-brq-testes-ios-1/FinanceApp/Service/NetworkClient.swift b/solutions/devsprint-brq-testes-ios-1/FinanceApp/Service/NetworkClient.swift index 40856ae8..d91d1ebe 100644 --- a/solutions/devsprint-brq-testes-ios-1/FinanceApp/Service/NetworkClient.swift +++ b/solutions/devsprint-brq-testes-ios-1/FinanceApp/Service/NetworkClient.swift @@ -13,12 +13,18 @@ protocol NetworkClientProtocol { } final class NetworkClient: NetworkClientProtocol { + + private let urlSession: URLSession + + init(urlSession: URLSession) { + self.urlSession = urlSession + } func performRequest(with url: URL, completion: @escaping (Data?) -> ()) { let request = URLRequest(url: url) - let task = URLSession.shared.dataTask(with: request) { data, response, error in + let task = urlSession.dataTask(with: request) { data, response, error in if let _ = error { completion(nil) diff --git a/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/NetworkClientTests.swift b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/NetworkClientTests.swift new file mode 100644 index 00000000..a45d4b22 --- /dev/null +++ b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/NetworkClientTests.swift @@ -0,0 +1,74 @@ +// +// NetworkClientTests.swift +// FinanceAppTests +// +// Created by Marcos Amorim Rossi de Carvalho on 20/11/22. +// + +import Foundation +import XCTest + +@testable import FinanceApp + +class NetworkClientTests: XCTestCase { + + enum MyError: Error { + case genericError + } + + private var urlSessionSpy = URLSessionSpy() + private lazy var sut = NetworkClient(urlSession: self.urlSessionSpy) + + var mockedJson = +""" +{ + "balance": 1, + "savings": 2, + "spendings": 3 +} +""".data(using: .utf8) + + func test_performRequest_gotCalledCorrectly() { + let urlToBePassed = URL(string: "https://www.notion.so/devpass/")! + + sut.performRequest(with: urlToBePassed, completion: { + _ in + XCTAssertTrue(self.urlSessionSpy.dataTaskCalled) + }) + + } + + func test_performRequest_shouldReturnCorrectData() { + let urlToBePassed = URL(string: "https://www.notion.so/devpass/")! + urlSessionSpy.setData(data: mockedJson!) + + sut.performRequest(with: urlToBePassed, completion: { + data in + XCTAssertEqual(data, self.mockedJson) + }) + + } + + func test_performRequest_shouldReturnNilData() { + let urlToBePassed = URL(string: "https://www.notion.so/devpass/")! + + sut.performRequest(with: urlToBePassed, completion: { + data in + XCTAssertNil(data) + }) + + } + + func test_performRequest_whenErrorAndDataAreNotNil_shouldReturnNilData() { + let urlToBePassed = URL(string: "https://www.notion.so/devpass/")! + urlSessionSpy.setData(data: mockedJson!) + urlSessionSpy.setError(error: MyError.genericError) + + sut.performRequest(with: urlToBePassed, completion: { + data in + XCTAssertNil(data) + }) + + } + +} diff --git a/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/NetworkClientSpy.swift b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/NetworkClientSpy.swift index fecc4ab4..aabe7fc5 100644 --- a/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/NetworkClientSpy.swift +++ b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/NetworkClientSpy.swift @@ -1 +1,19 @@ import Foundation + +@testable import FinanceApp + +final class NetworkClientSpy: NetworkClientProtocol { + + private(set) var performRequestCalled: Bool = false + private(set) var performRequestCallCount: Int = 0 + private(set) var performRequestURL: URL? + var performRequestCompletionDataToBeReturned: Data? + + func performRequest(with url: URL, completion: @escaping (Data?) -> ()) { + performRequestCalled = true + performRequestCallCount += 1 + performRequestURL = url + completion(performRequestCompletionDataToBeReturned) + } + +} diff --git a/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/URLSessionSpy.swift b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/URLSessionSpy.swift index fecc4ab4..9b2ed799 100644 --- a/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/URLSessionSpy.swift +++ b/solutions/devsprint-brq-testes-ios-1/FinanceAppTests/Test Doubles/URLSessionSpy.swift @@ -1 +1,34 @@ import Foundation + +final class URLSessionSpy: URLSession { + + private(set) var dataTaskCalled: Bool = false + private(set) var dataTaskData: Data? + private(set) var dataTaskResponse: URLResponse? + private(set) var dataTaskError: Error? + + override func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { + dataTaskCalled = true + completionHandler(dataTaskData, dataTaskResponse, dataTaskError) + return URLSessionDataTaskSpy() + } + + func setData(data: Data) { + dataTaskData = data + } + + func setResponse(response: URLResponse) { + dataTaskResponse = response + } + + func setError(error: Error) { + dataTaskError = error + } +} + +final class URLSessionDataTaskSpy: URLSessionDataTask { + + override func resume() { + + } +}