Shared instance and unit testing properties

In the below code there is CarServices.shared which initializes the oilChangeService type with an OilChange object.

public final class CarServices {
    public static let shared = CarServices()
    
    public let oilChangeService: MaintenanceService
    
    private init() {
        oilChangeService = OilChange()
    }
}

public protocol MaintenanceService: Actor {
    func performMaintenance() async
}

actor OilChange: MaintenanceService {
    public func performMaintenance() async {
        print("Oil Change Service Performed")
    }
}

However while writing unit tests, if we want to Mock it with a different class any idea how to configure the shared instance, as during unit tests it will still refer to OilChange object instead of MockOilChange.

Is there a better approach to this?

actor MockOilChange: MaintenanceService {
    public func performMaintenance() async {
        print("Mocked Oil Change Service Performed")
    }
}

Yes. The usage of existentials should tip you off to it. When you switch to using generics, you can no longer store a shared instance*—instead, you need to move its storage to wherever it belongs, in your code.

public final class CarServices<OilChangeService: MaintenanceService> {
  public let oilChangeService: OilChangeService

  public init(oilChangeService: OilChangeService = OilChange()) {
    self.oilChangeService = oilChangeService
  }
}

public actor OilChange: MaintenanceService {
  @usableFromInline init() { }
CarServices() // CarServices<OilChangeService> by default.
CarServices(oilChangeService: MockOilChange())

* Your code actually won't compile as you wrote it, because CarServices is not Sendable.