TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Unit Testing with the Singleton

Forums > Swift

Hey guys.

I try to understand how to create dependency injection with the Singleton in order to test it. Due to its private init() {} you cant create an instance of it in your code.

Now, I have seen some techniques where people change private init() {} to init() {} and create a subclass of that Singletone with override init.

From what I understand, the very essence of Signleton is exactly to have its initialiser private.

Is this still a legit way to do so? Is there a way to create that dependency injection while keeping my Singleton's initialiser private?

Many thank for any help!


You would be best off getting rid of the singletons and just injecting in the service to your view models. I've provided an example below with some networking, which is a common place where people use singletons. I have used Combine here, but you can just replace all that with closures if required. Basically, you create a Protocol that the Mock and Live must conform each of the required methods. You can then inject the an APIClientProtocol into the view model, with a default of live to make the code nicer. And then for testing you can inject in the MockAPIClient which will not hit the actual network.

import Combine
import Foundation

struct User: Decodable, Identifiable {
    let id: Int
    let name: String

protocol APIClientProtocol {
    func getPosts() -> AnyCancellable<[User], Error>

struct MockAPIClient: APIClientProtocol {
    func getPosts() -> AnyCancellable<[User], Error> {
        // mock test logic here

struct APIClient: APIClientProtocol {
    func getPosts() -> AnyCancellable<[User], Error> {
        // live logic here

class UsersViewModel: ObservableObject {
    private let apiClient: APIClientProtocol
    private var cancellables = Set<AnyCancellable>()

    @Published var users = [User]()

    init(apiClient: APIClientProtocol = APIClient()) {
        self.apiClient = apiClient

    func getUsers() {
            .sink { completion in
                switch completion {
                case .finished: break
                case .failure(let error):
                } receivedValue: { [weak self] users in
                    self?.users = users
                .store(in: &cancellables)

// testing the ViewModel

let testViewModel = UsersViewModel(apiClient: MockAPIClient())
// ...


Hacking with Swift is sponsored by Superwall.

SPONSORED Superwall lets you build & test paywalls without shipping updates. Run experiments, offer sales, segment users, update locked features and more at the click of button. Best part? It's FREE for up to 250 conversions / mo and the Superwall team builds out 100% custom paywalls – free of charge.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.