Closed heckj closed 4 years ago
Any contributions are welcome! As long as it's an optional feature and not hurting anyone else already using the project :)
Feel free to open the PR!
Closing this one for inactivity. Feel free to reopen!
Hello @AvdLee I'm converting some manual mocked tests to your framework, however, I'm a bit surprised to see this failed interactions feature missing.
Is there another way you test error handling? I can not see a way to cover the handling of my certificate pinning errors and some other scenario's such as no connection at all to the server.
I'm BTW using Alamofire 5
Could you share your usage and experience with that?
How could a solution look?
Would the onRequest
or completion
method be allowed to throw errors or would there be a separate setter which can be assigned an Error
to be passed to a call to urlProtocol .. didFailWithError
@martinvw you can mock any request with failure response codes and optionally JSON data matching the error just like you would with other mocks:
https://github.com/WeTransfer/Mocker/blob/master/MockerTests/MockerTests.swift#L71
@AvdLee sorry for the confusion, I was referring to errors other then HTTP-errors, see the example I gave above as well:
I can not see a way to cover the handling of my certificate pinning errors and some other scenario's such as no connection at all to the server.
Or do the frameworks such as Alamofire use other (negative?) status codes for that?
@martinvw how would you normally test this? Wouldn't this be out of scope for this framework? Mocker focuses on mocking outgoing network requests. I feel like these are failures happening before a request is going out.
Correct me if I'm wrong!
Otherwise, if you do think the framework should be capable of doing so, we can look into adding the functionality 🙂
How would you normally test this?
I had the following code to test the URLSession
and I added an extension on top of the URLSession
to implement the URLSessionProtocol
class MockUrlSession: URLSessionProtocol {
var capturedRequests = [URLRequest]()
var mockedData: Data?
var mockedResponse: URLResponse?
var mockedError: Error?
func dataTask(on request: URLRequest, completionHandler: @escaping DataTaskResult) -> URLSessionDataTaskProtocol {
capturedRequests.append(request)
completionHandler(mockedData, mockedResponse, mockedError)
return MockURLSessionDataTask()
}
}
...
class MockURLSessionDataTask: URLSessionDataTaskProtocol {
func resume() {
}
}
Wouldn't this be out of scope for this framework?
I think that is up to you to decide :-D
I don't think it's out of scope because any solution implementing would be mocking the same classes en doing the same calls.
From the above example I don't see anything that is not yet possible. Can you share with me one of your tests that you're currently not able to perform with Mocker?
Thanks you very much for your reply I will try to come up with a clear verbose example tomorrow. I was busy with some other problems today.
Thanks for your time!
So it's about setting the mockedError
in the snippet above, the original issue starter solved it here:
My test did, for example, do the following:
func testReportingFailsError() throws {
mockSession.mockedError = TestError.testError
errorSubject.report(communication: Communication.init(...], context: context), onSuccess: {
XCTFail("Expected an error")
}, onError: {
self.expectation.fulfill()
})
waitForExpectations(timeout: 1.0) { (_) in
let reported = self.mockErrorLogger.reported
XCTAssertEqual(1, reported.count)
XCTAssertEqual("Invalid response received from server: empty", reported.first!.0)
XCTAssertTrue(reported.first!.1! as? TestError == TestError.testError)
}
}
And now I also want to create a test which throws the same error as the error thrown when the certificate pinning fails, it could, for example, look like this:
func testReportingFailsToPin() throws {
var mock = Mock(url: noPinCommunicationUrl, dataType: .json, failure: [.post: AFError.serverTrustEvaluationFailed(reason: Alamofire.AFError.ServerTrustFailureReason.noPublicKeysFound)])
mock.register()
errorSubject.report(communication: Communication.init(...)], context: context), onSuccess: {
XCTFail("Expected an error")
}, onError: {
self.expectation.fulfill()
})
waitForExpectations(timeout: 10.0) { (_) in
let reported = self.mockErrorLogger.reported
XCTAssertEqual(1, reported.count)
XCTAssertEqual("Failed to validate trust: noPublicKeysFound", reported.first!.0)
XCTAssertTrue(reported.first!.1! as? TestError == Alamofire.AFError.ServerTrustFailureReason.noPublicKeysFound)
}
}
Even when configuring the correct pinning in the test alamofire will not respond correctly.
I sort of hacked that on to the side of the Mock, not sure what API would be good/appropriate, so I could use it to generate apparent "failures" within combine flows, and verify the flows were reacting to the failures appropriately. I meant to refactor that out and submit as a PR to Mock so others might have it, but lost track...
@martinvw It's missing some pieces that I'm guessing the project will require (like docs, tests) - but the core of how I was using it is here: https://github.com/WeTransfer/Mocker/pull/52 - refactored to drop over the most recent version of Mocker rather than my earlier hacked/forked copy.
I think it's fine to add such a feature if that helps for your cases! I'll go and reply in the PR for the feedback I have 🙂
I didn't see any clear means of returning a failed network interaction (no route to host, for example) with Mocker, but I wanted that for some testing of my own.
I've made a slight modification in a forked version that has an additional initializer ('reportFailure' - a boolean) that will return throw exception on URL access instead of returning Data & a response code. Is this something you'd like as a pull request?
I wanted to offer, but wasn't sure how/if you wanted contributions to this library. I'm using it a bit differently than it was originally designed - more for testing failure scenarios, but it served me pretty well where I needed it: forked variant at https://github.com/heckj/swiftui-notes/blob/master/UsingCombineTests/Mock.swift