-1

I have a class with few public and private members like below :

public class ReviewManager {
    
    public static let shared = ReviewManager()
    
    private static let startDateKey = "StartDate"
    private static let popupLastSeenKey = "LastSeen"
    private static let lastVersionPromptedForReview = "lastVersionPromptedForReview"
    
    private(set) var startDate: Date {
        get {
             Date()
        }
        set { }
    }
    
    private(set) var lastPopupDate: Date? {
        get {
            
        }
        set {
           
        }
    }
    
    private(set) var lastVersionPromptedForReview: String {
        get {
            
        }
        
        set {
            
        }
    }
    
    private(set) var appCurrentVersion: String {
        
        get {
            // Get the current bundle version for the app
            guard let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
            else {
                logError("Expected to find a bundle version in the info dictionary")
                return ""
            }
            
            return currentVersion
        }
        set { }
        
    }
    
    private func requestReview() {
        
        SKStoreReviewController.requestReview()
        
        lastPopupDate = Date()
        lastVersionPromptedForReview = appCurrentVersion
    }
    
    public func requestReviewIfPossible() {
        
        
        let today = Date()
        
        if lastPopupDate == nil {
            if allowedToPresentToday() && allowedToPresentForThisVersion() {
                requestReview()
            }
        } else {
            if let lastPopupDate = lastPopupDate {
                if allowedToPresentToday() && allowedToPresentForThisVersion() {
                    requestReview()
                }
            }
        }
    }
    
    private func allowedToPresentToday() -> Bool {
        let calendar = Calendar(identifier: .gregorian)
        let today = Date()
        let components = calendar.dateComponents([.weekday], from: today!)
        
        return components.weekday == 5 || components.weekday == 6
    }
    
    private func allowedToPresentForThisVersion() -> Bool {
        
        let allowedToShowForThisVersion = (appCurrentVersion != lastVersionPromptedForReview) ? true : false
        return allowedToShowForThisVersion
    }
}

Now I want to write Unit tests for all the private functions in this class. I can access private properties in this class by making access modifier as

private(set)

But private functions can not be accessed outside the class.

Is there any way to unit test private functions in Swift ?

  • 2
    You should test the public interface of the class (`requestReviewIfPossible`), private methods do not matter / do not exist in terms of testing. – luk2302 May 05 '21 at 07:16
  • I have faced same problem. For Unit Test u have to make them public. – Kudos May 05 '21 at 07:51
  • 2
    The first comment is correct, the second one is incorrect. You test your type using its public API and you never change the API just for unit tests. With proper tests all private methods and properties will be covered when testing the public API – Joakim Danielson May 05 '21 at 09:39
  • Off topic but don't add `get/set` to a property if you don't have any code for them. – Joakim Danielson May 05 '21 at 09:45

1 Answers1

0

Completely echo @luk2302, in that you should be testing the public interface. But if you feel you really must, perhaps consider creating a wrapper function around the private function to expose it. You could make this compile conditionally, say in this example only in DEBUG mode, so it doesn't pollute your production code:

class MyClass {
    private func myPrivateFunc() -> Void {
        print("Hello")
    }
}

#if DEBUG
extension MyClass {
    func myPublicFunc() -> Void {
        myPrivateFunc()
    }
}
#endif

let myClass = MyClass()

myClass.myPublicFunc()
Philip Pegden
  • 1,732
  • 1
  • 14
  • 33