diff --git a/Mocker.xcodeproj/project.pbxproj b/Mocker.xcodeproj/project.pbxproj index e8833df..5aa2ece 100644 --- a/Mocker.xcodeproj/project.pbxproj +++ b/Mocker.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 501B8FC4247E89C600B885F4 /* XCTest+Mocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501B8FC3247E89C600B885F4 /* XCTest+Mocker.swift */; }; 501E269E1F3DAE370048F39E /* Mocker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 501E26941F3DAE370048F39E /* Mocker.framework */; }; 503446171F3DB4660039D5E4 /* Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503446141F3DB4660039D5E4 /* Mock.swift */; }; 503446181F3DB4660039D5E4 /* Mocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503446151F3DB4660039D5E4 /* Mocker.swift */; }; @@ -28,6 +29,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 501B8FC3247E89C600B885F4 /* XCTest+Mocker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTest+Mocker.swift"; sourceTree = ""; }; + 501B8FC5247E8BDE00B885F4 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 501E26941F3DAE370048F39E /* Mocker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Mocker.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 501E269D1F3DAE370048F39E /* MockerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MockerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 501F8B2D237594AC008EF77E /* Mocker.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Mocker.podspec; sourceTree = ""; }; @@ -65,6 +68,7 @@ 501E268A1F3DAE370048F39E = { isa = PBXGroup; children = ( + 501B8FC5247E8BDE00B885F4 /* README.md */, 506277CC235F2777000A4316 /* Changelog.md */, 501F8B2D237594AC008EF77E /* Mocker.podspec */, 501E26951F3DAE370048F39E /* Products */, @@ -89,6 +93,7 @@ 503446141F3DB4660039D5E4 /* Mock.swift */, 503446151F3DB4660039D5E4 /* Mocker.swift */, 503446161F3DB4660039D5E4 /* MockingURLProtocol.swift */, + 501B8FC3247E89C600B885F4 /* XCTest+Mocker.swift */, ); path = Sources; sourceTree = ""; @@ -264,6 +269,7 @@ buildActionMask = 2147483647; files = ( 503446191F3DB4660039D5E4 /* MockingURLProtocol.swift in Sources */, + 501B8FC4247E89C600B885F4 /* XCTest+Mocker.swift in Sources */, 503446181F3DB4660039D5E4 /* Mocker.swift in Sources */, 503446171F3DB4660039D5E4 /* Mock.swift in Sources */, ); @@ -419,6 +425,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks\n$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); INFOPLIST_FILE = "Mocker/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -439,6 +448,9 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks\n$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); INFOPLIST_FILE = "Mocker/Supporting Files/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 10.0; diff --git a/MockerTests/MockerTests.swift b/MockerTests/MockerTests.swift index f52d82b..337576f 100644 --- a/MockerTests/MockerTests.swift +++ b/MockerTests/MockerTests.swift @@ -346,6 +346,32 @@ final class MockerTests: XCTestCase { request.httpMethod = Mock.HTTPMethod.put.rawValue XCTAssertNotNil(Mocker.mock(for: request)) } + + /// It should call the on request expectation. + func testOnRequestExpectation() { + let url = URL(string: "https://www.fakeurl.com")! + + var mock = Mock(url: url, dataType: .json, statusCode: 200, data: [.get: Data()]) + let expectation = expectationForRequestingMock(&mock) + mock.register() + + URLSession.shared.dataTask(with: URLRequest(url: url)).resume() + + wait(for: [expectation], timeout: 2.0) + } + + /// It should call the on completion expectation. + func testOnCompletionExpectation() { + let url = URL(string: "https://www.fakeurl.com")! + + var mock = Mock(url: url, dataType: .json, statusCode: 200, data: [.get: Data()]) + let expectation = expectationForCompletingMock(&mock) + mock.register() + + URLSession.shared.dataTask(with: URLRequest(url: url)).resume() + + wait(for: [expectation], timeout: 2.0) + } /// it should return the error we requested from the mock when we pass in an Error. func testMockReturningError() { @@ -374,6 +400,5 @@ final class MockerTests: XCTestCase { }.resume() waitForExpectations(timeout: 10.0, handler: nil) - } } diff --git a/README.md b/README.md index ed0daaf..57e887c 100644 --- a/README.md +++ b/README.md @@ -188,22 +188,6 @@ let ignoredURL = URL(string: "www.wetransfer.com")! Mocker.ignore(ignoredURL) ``` -##### Mock callbacks -You can register on `Mock` callbacks to make testing easier. - -```swift -var mock = Mock(url: request.url!, dataType: .json, statusCode: 200, data: [.post: Data()]) -mock.onRequest = { request, postBodyArguments in - XCTAssertEqual(request.url, mock.request.url) - XCTAssertEqual(expectedParameters, postBodyArguments as? [String: String]) - onRequestExpectation.fulfill() -} -mock.completion = { - endpointIsCalledExpectation.fulfill() -} -mock.register() -``` - ##### Mock errors You can request a `Mock` to return an error, allowing testing of error handling. @@ -227,6 +211,36 @@ URLSession.shared.dataTask(with: originalURL) { (data, urlresponse, err) in }.resume() ``` +##### Mock callbacks +You can register on `Mock` callbacks to make testing easier. + +```swift +var mock = Mock(url: request.url!, dataType: .json, statusCode: 200, data: [.post: Data()]) +mock.onRequest = { request, postBodyArguments in + XCTAssertEqual(request.url, mock.request.url) + XCTAssertEqual(expectedParameters, postBodyArguments as? [String: String]) + onRequestExpectation.fulfill() +} +mock.completion = { + endpointIsCalledExpectation.fulfill() +} +mock.register() +``` + +##### Mock expectations +Instead of setting the `completion` and `onRequest` you can also make use of expectations: + +```swift +var mock = Mock(url: url, dataType: .json, statusCode: 200, data: [.get: Data()]) +let requestExpectation = expectationForCompletingMock(&mock) +let completionExpectation = expectationForCompletingMock(&mock) +mock.register() + +URLSession.shared.dataTask(with: URLRequest(url: url)).resume() + +wait(for: [requestExpectation, completionExpectation], timeout: 2.0) +``` + ## Communication - If you **found a bug**, open an issue. diff --git a/Sources/Mock.swift b/Sources/Mock.swift index 01ef24a..6f5eb0d 100644 --- a/Sources/Mock.swift +++ b/Sources/Mock.swift @@ -9,6 +9,7 @@ // swiftlint:disable force_unwrapping import Foundation +import XCTest /// A Mock which can be used for mocking data requests with the `Mocker` by calling `Mocker.register(...)`. public struct Mock: Equatable { @@ -103,6 +104,12 @@ public struct Mock: Equatable { /// The callback which will be executed everytime this `Mock` was started. Can be used within unit tests for validating that a request has been started. The callback must be set before calling `register`. public var onRequest: OnRequest? + + /// Can only be set internally as it's used by the `expectationForRequestingMock(_:)` method. + var onRequestExpectation: XCTestExpectation? + + /// Can only be set internally as it's used by the `expectationForCompletingMock(_:)` method. + var onCompletedExpectation: XCTestExpectation? private init(url: URL? = nil, ignoreQuery: Bool = false, dataType: DataType, statusCode: Int, data: [HTTPMethod: Data], requestError: Error? = nil, additionalHeaders: [String: String] = [:], fileExtensions: [String]? = nil) { self.urlToMock = url diff --git a/Sources/MockingURLProtocol.swift b/Sources/MockingURLProtocol.swift index c2a1172..de2f1ee 100644 --- a/Sources/MockingURLProtocol.swift +++ b/Sources/MockingURLProtocol.swift @@ -46,6 +46,7 @@ public final class MockingURLProtocol: URLProtocol { if let onRequest = mock.onRequest { onRequest(request, request.postBodyArguments) } + mock.onRequestExpectation?.fulfill() guard let delay = mock.delay else { finishRequest(for: mock, data: data, response: response) @@ -72,6 +73,7 @@ public final class MockingURLProtocol: URLProtocol { } mock.completion?() + mock.onCompletedExpectation?.fulfill() } /// Implementation does nothing, but is needed for a valid inheritance of URLProtocol. diff --git a/Sources/XCTest+Mocker.swift b/Sources/XCTest+Mocker.swift new file mode 100644 index 0000000..f61576f --- /dev/null +++ b/Sources/XCTest+Mocker.swift @@ -0,0 +1,24 @@ +// +// XCTest+Mocker.swift +// Mocker +// +// Created by Antoine van der Lee on 27/05/2020. +// Copyright © 2020 WeTransfer. All rights reserved. +// + +import Foundation +import XCTest + +public extension XCTestCase { + func expectationForRequestingMock(_ mock: inout Mock) -> XCTestExpectation { + let mockExpectation = expectation(description: "\(mock) should be requested") + mock.onRequestExpectation = mockExpectation + return mockExpectation + } + + func expectationForCompletingMock(_ mock: inout Mock) -> XCTestExpectation { + let mockExpectation = expectation(description: "\(mock) should be finishing") + mock.onCompletedExpectation = mockExpectation + return mockExpectation + } +} diff --git a/Submodules/WeTransfer-iOS-CI b/Submodules/WeTransfer-iOS-CI index 4a87331..3e47cf7 160000 --- a/Submodules/WeTransfer-iOS-CI +++ b/Submodules/WeTransfer-iOS-CI @@ -1 +1 @@ -Subproject commit 4a87331db4963edd63c54c7dd79f896862989238 +Subproject commit 3e47cf737031a2a0240e0d0722ec87b4bca683a8