'How to mock a generic implementation of a protocol?
I'm trying to do some dependency injection in order to unit test, and also make iOS live preview easier.
I have a Store protocol, and I want to use these in my SUT classes so I can pass mock implementations.
protocol Store {
associatedtype AnyData
func load() -> AnyData?
func save(data anyData: AnyData)
}
class FileStore<AnyData: Codable>: Store {
func load() -> AnyData? { /* Actual code that saves to a file */ }
func save(data anyData: AnyData) { /* Actual code that saves to a file */ }
}
class MockStore<AnyData: Codable>: Store {
func load() -> AnyData? { /* Returns mocked value for unit testing */ }
func save(data anyData: AnyData) { /* Returns mocked value for unit testing */ }
}
However, in my SUT class I have the following:
class MyClassToBeTested {
// THIS DOESN'T WORK
let bookStore: Store // ERROR: Protocol 'Store' can only be used as a generic
// constraint because it has Self or associated type requirements
// DOESN'T WORK EITHER
let studentStore: Store<Student> // ERROR: Cannot specialize non-generic type 'Store'
}
// in real app
MyClassToBeTested(
bookStore: FileStore<Book>()
studentStore: FileStore<Student>()
)
// in test or preview
MyClassToBeTested(
bookStore: MockStore<Book>()
studentStore: MockStore<Student>()
)
Seems like I'm stuck. I'm essentially trying to have a generic protocol, similar to a generic interface in Java. What am I missing?
UPDATE
Following @Jessy answer, I did:
class MyClassToBeTested<BookStore: Store, StudentStore: Store>
where
BookStore.AnyData == Book,
StudentStore.AnyData == Student
{
let bookStore: BookStore
let studentStore: StudentStore
Which solves half of the issue. The other half is how to type a variable with it:
class OtherClass {
var sut: MyClassToBeTested // ERROR: Generic parameter Bookstore could not be inferred
var sut2: MyClassToBeTested< // I know this isn't supported in Swift
Store<Book>, // but can't figure out the right syntax
Store<Student> // ERROR: Cannot specialize non-generic type 'Store'
> // ERROR: Protocol 'Store' as a type cannot conform to the protocol itself
var sut3: MyClassToBeTested< // Compiles, BUT I cannot pass a
FileStore<Book>, // MockStore in my tests/preview
FileStore<Student> // so it's useless
>
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
