Unit Test class from iOS I am learning to write test cases in iOS using Swift. I was stuck at testing static functions from my Utilities class, so I tried to mock that class and then test the cases. Please let me know if its the correct approach or else tell me how to do that. Here is my code:

import XCTest
@testable import ConnectAndSell

class UtilitiesMock{
    func getBuildNumber() -&gt; String{
        return Utilities.getAppBuildNumber()
    }
    func getVersionNumber() -&gt; String{
        return Utilities.getAppVersion()
    }
}

class UtilitiesTests: XCTestCase {
    //system under test
    var sut:UtilitiesMock!

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
        sut = UtilitiesMock()
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
        sut = nil
    }

    func testBuildNumber() {
        let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as! String
        XCTAssertEqual(buildNumber, sut.getBuildNumber())

    }

    func testVersionNumber() {
        let versionNumber = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String
        XCTAssertEqual(versionNumber, sut.getVersionNumber())
    }

}


EDIT: Adding Utilities class so that you guys can see what am I trying to test. It's just simple functions to verify the current build number and version number. I have taken these function just for example. My main aim is to know is it the correct approach to test static methods. 

import Foundation

class Utilities {

    static func getAppVersion() -&gt; String {
        if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
            log.debug("App verison: \(version)")
            return version
        }
        return ""
    }
    static func getAppBuildNumber() -&gt; String {
        if let number = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
            log.debug("Build number: \(number)")
            return number
        }
        return ""
    }

}
Unit Tests should not have a dependency on the application bundle at runtime which could not be injected on the init phase or by a method arguments


The given Utility class has a static methods which act like a shortcuts to longer syntax calls. This methods calls directly methods on Bundle class object which is cannot be mocked. The solution is to move Bundle -&gt; infoDictionary outside of a method and set it as a static property. Now, in the app the dictionary can reference a dictionary from the app bundle and in test bundle will reference a mocked dictionary. The main purpose of a unit testing this methods will be to validate usage of given dictionary and keys to access demanded values.


Utility methods aka class methods are not dependency injection friendly and that makes them more complicated to test
UtilitiesMock is not a mock, it's more a proxy / facade / wrapper class


Solution:

protocol BundleInfoDictionaryShortcuts {
    static var bundleMainInfoDictionary: [String : Any]? { get set }
}

enum BundleInfoDictionary: String {
    case keyCFBundleShortVersionString = "CFBundleShortVersionString"
    case keyCFBundleVersion = "CFBundleVersion"
}

class Utilities: BundleInfoDictionaryShortcuts {

    static var bundleMainInfoDictionary: [String : Any]? = Bundle.main.infoDictionary

    static func getAppVersion() -&gt; String {

        guard let version = bundleMainInfoDictionary?[BundleInfoDictionary.keyCFBundleShortVersionString.rawValue] as? String else {
            fatalError()
        }
        return version
    }

    static func getAppBuildNumber() -&gt; String {
        guard let number = bundleMainInfoDictionary?[BundleInfoDictionary.keyCFBundleVersion.rawValue] as? String else {
            fatalError()
        }
        return number
    }
}




// File: BundleInfoDictionaryShortcutsTests.swift

class BundleInfoDictionaryShortcutsTests: XCTestCase {
        static let appVersion = "1.0.1"
        static let appBuildNumber = "120"

        override class func setUp() {
            super.setUp()
            Utilities.bundleMainInfoDictionary = [
                BundleInfoDictionary.keyCFBundleShortVersionString.rawValue: appVersion,
                BundleInfoDictionary.keyCFBundleVersion.rawValue: appBuildNumber
            ]
        }

        func testGetAppVersion() {
            XCTAssertEqual(Utilities.getAppVersion(), Self.appVersion)
        }
        func testGetAppBuildNumber() {
            XCTAssertEqual(Utilities.getAppBuildNumber(), Self.appBuildNumber)
        }
    }




// File: BundleInfoDictionaryShortcutsTests.swift

    class BundleInfoDictionaryTests: XCTestCase {
        func testKeys() {
            XCTAssertEqual(BundleInfoDictionary.keyCFBundleShortVersionString.rawValue,"CFBundleShortVersionString")
            XCTAssertEqual(BundleInfoDictionary.keyCFBundleVersion.rawValue,"CFBundleVersion")
        }
    }