I'm building a simple app to practice app architecture, working with protocols, associated types, etc. I think I'm using a pretty common pattern that I've used and seen many times before, however I'm running into this compiler error and I haven't been able to figure out or find the solution yet: Argument type 'AMock' does not conform to expected type 'AProtocol'
I'm guessing it's something very basic and embarrassing, however perhaps this will be useful to someone in a similar situation :)
Here's the protocol:
protocol AProtocol {
func a() -> String
}
I'm selecting both the app and the test targets for it:
Here's the class conforming to this protocol:
class A: AProtocol {
func a() -> String {
return "a"
}
}
And here's a class where I'm using this protocol for dependency injection:
class B {
private let aClass: AProtocol
init(aClass: AProtocol) {
self.aClass = aClass
}
func returnString() -> String {
return aClass.a()
}
}
So far so good, the code compiles. I'd like to use the above for testing, so I'm setting up a mock:
class AMock: AProtocol {
func a() -> String {
return "mock"
}
}
And adding the following to my XCTest setup:
import XCTest
@testable import ProtocolPractice
final class ProtocolPracticeTests: XCTestCase {
var sut: B!
var aMock: AMock!
override func setUpWithError() throws {
aMock = AMock()
sut = B(aClass: aMock) // Argument type 'AMock?' does not conform to expected type 'AProtocol'
}
func test() throws {
XCTAssertEqual(sut.returnString(), "mock")
}
}
Does anyone know why the compiler thinks that AMock does not conform to AProtocol? To me it seems that it does, and there are no compile errors in the AMock file itself, only in my test file. I've seen this pattern used before and used it myself many times, and I've found examples of it as well, like this one.
Xcode suggests that I Insert ' as! AProtocol'
but that doesn't make the issue go away.
I've also tried using var aMock: AProtocol!
in the test (in place of var aMock: AMock!
) and I get a similar error: Argument type '(any AProtocol)?' does not conform to expected type 'AProtocol'
In case this matters, I'm using Xcode 15.4 with Swift 5.
I'm selecting both the app and the test targets for it:
This is the basic problem, because it means that AProtocol
exists in two modules: ProtocolPractice.AProtocol
and ProtocolPracticeTests.AProtocol
.
Your code for AMock
therefore references AProtocol
from the ProtocolPracticeTests
module and not the one from your App.
This is why the compiler error occurs, because ProtocolPractice.AProtocol
and ProtocolPracticeTests.AProtocol
are two different protocols.
The following code would therefore theoretically solve the problem:
class AMock: ProtocolPractice.AProtocol {
func a() -> String {
return "mock"
}
}
But you shouldn't do that!
You should remove AProtocol
from the test target. With @testable import ProtocolPractice
you get access to the internal declarations of the ProtocolPractice
module.
So for your mock implementations of your test target, you only need to add this import statement.
@testable import ProtocolPractice
class AMock: AProtocol {
func a() -> String {
return "mock"
}
}