Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock EKEventStore

I have a simple function for requesting access for adding events in the Calendar.

typealias BoolCallback = (Bool) -> ()

class SimpleCalendar {

    let store: EKEventStore

    init(store: EKEventStore = EKEventStore()) {
        self.store = store
    }

    /// Request access to EventKit API for Calendar intergration
    ///
    /// - Parameter callback: returns if access was recived or denied
    func requestAccess(callback: @escaping BoolCallback) {

        let status = EKEventStore.authorizationStatus(for: .event)

        switch status {
        case .authorized:
            callback(true)
            //        case .notDetermined: //should ask for access
        //        case .denied, .restricted: //should open a ask permission view
        default:
            store.requestAccess(to: .event) { accessGranted, _ in

                DispatchQueue.main.async {
                    callback(accessGranted)
                }
            }
        }


    }
}

Is there a way to mock EKEventStore for getting the status?

I also have a simple function that checks if a calendar exists.

func doesCalendarExist(name: String) -> Bool {
    let calendars = store.calendars(for: .event)

    if calendars.contains(where: { $0.title == name }) {
        return true
    }

    return false
}

Is there a way to mock the store objects for getting store.calendars

Thanks


I switched

let status = EKEventStore.authorizationStatus(for: .event)

to

let status = type(of: store).authorizationStatus(for: .event)
like image 749
ilan Avatar asked Mar 21 '26 00:03

ilan


1 Answers

I think you can use DI here. Instead of put responsibility of creating store var inside of SimpleCalendar you can create constructor for it with parameter store: EKEventStore and pass it there:

init(store: EKEventStore = EKEventStore()) {/*code*/}

This way, you can pass your own mock object.

What is the issue with overriding class method? I can't check it right now, but suppose it's possible.

Any way, other option is for mocking you can create protocol with all the methods you're using - EventStoreProtocol. These methods must be in EKEventStore I think, so you can easily adopt it using extension:

extension EKEventStore: EventStoreProtocol {}

Then instead of passing EKEventStore to constructor, pass there EventStoreProtocol.

Your mock object will be not subclass, but just class confirming to that protocol, implementing all required methods

For class method, instead of EKEventStore.authorizationStatus use type(of: store).authorizationStatus

The only thing I can think of regarding your problem is the next:

extension EKEventStore {
   func eventAuthorizationStatus() -> EKAuthorizationStatus {
      return EKEventStore.authorizationStatus(for: .event)
   }
}

Then override this method in subclass. Because EKEventStore is NSObject, it should work (but I'm not sure). This way instead of using type(of: store).authorizationStatus you can call this method.

But the question - do you really need this? Can't you just left it as is? If no, check this approach and tell me, if it works

like image 89
Vladyslav Zavalykhatko Avatar answered Mar 23 '26 13:03

Vladyslav Zavalykhatko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!