Search code examples
swiftunit-testingxctestcase

Test returns "Type of expression is ambiguous without more context" on func that throws


I am writing a network layer, following a TDD approach.

I have a struct that I will be using to encode any parameters in my request.

I would like to assert that should a URL be missing / nil when invoking this encoder, the correct error is thrown.

struct URLParameterEncoder: ParameterEncoder {
    static func encode(urlRequest: inout URLRequest, with parameters: Parameters) throws {
        guard let url = urlRequest.url else { throw NetworkError.missingURL }
    }
}

I have written a test and passed in a URL which I believe should satisfy this test, however am getting an error when trying to run the test.

class URLParameterEncoderTests: XCTestCase {
    var sut: URLParameterEncoder!

    override func setUp() {
        sut = URLParameterEncoder()
    }

    func test_Encode_ThrowsMissingURLError_WhenURLIsNil() {
        let request = URLRequest(url: URL(string: "")!)
        let params: Parameters = [:]

        XCTAssertThrowsError(try sut.encode(urlRequest: &request, with: params)) { error in
            XCTAssertEqual(error as? NetworkError, NetworkError.missingURL)
        }
    }
}

In my XCTAssertThrowsError I am getting Type of expression is ambiguous without more context which I believe is being triggered around sut.encode

Additional code required to replicate

public typealias Parameters = [String: Any]

public protocol ParameterEncoder {
    static func encode(urlRequest: inout URLRequest, with parameters: Parameters) throws
}

public enum NetworkError: String, Error {
    case paramsAreNil = "Missing params"
    case encodingFailed = "Could not encode params"
    case missingURL = "Request URL is missing"
}

Solution

  • After adding more context – a question mark for optional chaining because sut is still an optional –

    XCTAssertThrowsError(try sut?.encode(urlRequest: &request, with: params)) { error in ...
    

    you get the real error

    Static member 'encode' cannot be used on instance of type 'URLParameterEncoder'

    It means that encode must be called on the type URLParameterEncoder.encode(...


    However this raises a new error

    Cannot pass immutable value as inout argument: 'request' is a 'let' constant

    That means an inout parameter like request must be declared as variable: var request = ...