Search code examples
swiftgenericsxctestswift-protocols

Mocking a generic class in Swift


I have a class for that I want to write unit test. This class has a dependency, which is a generic class, that I want to mock.

This is the class I want to test.

class ClassToTest: SomeProtocol {
    
    private let dependency = DependencyClass<AnotherClass>()
    
    init() {
        //Some Code Here
    }
}

class DependencyClass<General: AnotherClassProtocol> {
    func getData(from general: General) -> AnyPublisher<Data, Error> {
        //Some Code Here
    }
}

What I tried

class ClassToTest: SomeProtocol {
    
    private let dependency: DependencyClassProtocol
    
    init(_ dependency: DependencyClassProtocol = DependencyClass<AnotherClass>()) {
        //Some Code Here
        self. dependency = dependency
    }
}

class DependencyClass<General: AnotherClassProtocol>: DependencyClassProtocol {
    func getData(from general: General) -> AnyPublisher<Data, Error> {
        //Some Code Here
    }
}

protocol DependencyClassProtocol {
    associatedtype General
    func getData(from general: General) -> AnyPublisher<Data, Error> 
}

This approach gives me error "Protocol can an only be used as a generic constraint because it has Self or associated type requirements".

How can I Mock the DependencyClass to test the exact behaviour of ClassToTest.


Solution

  • I have not removed the generic constraints from the DependencyClass<General: AnotherClassProtocol> and also not added the type alias in the class definition. As soon as I did these changes it worked.

    import Combine
    import Foundation
    
    protocol DependencyClassProtocol {
        associatedtype General
        func getData(from general: General) -> AnyPublisher<Data, Error>?
    }
    
    class ClassToTest: SomeProtocol {
        
        private let dependency: any DependencyClassProtocol
        
        init(_ dependency: any DependencyClassProtocol = DependencyClass()) {
            //Some Code Here
            self.dependency = dependency
        }
    }
    
    class DependencyClass: DependencyClassProtocol {
        typealias General = AnotherClassProtocol
        
        func getData(from general: General) -> AnyPublisher<Data, Error>? {
            return nil
        }
    }
    
    class MockDependencyClass: DependencyClassProtocol {
        typealias General = AnotherClassProtocol
        
        func getData(from general: General) -> AnyPublisher<Data, Error>? {
            return nil
        }
    }
    
    protocol AnotherClassProtocol {
        
    }
    
    protocol SomeProtocol {
        
    }
    
    class AnotherClass: AnotherClassProtocol {}
    
    let ctt = ClassToTest(MockDependencyClass())