'Mocking CKContainer for Unit Testing

I am using CloudKit in my application and am trying to mock CKContainer to test my Managers. Here is what i tried:

    func testAccountStatus() {

class MockCloudContainer: CKContainer {

  override func accountStatusWithCompletionHandler(completionHandler: ((CKAccountStatus, NSError!) -> Void)!)
  {
    completionHandler(CKAccountStatus.NoAccount, NSError())
  }
}

let loginManager = LoginManager.sharedInstance
let expectation = expectationWithDescription("iCloudStatus")

var isTestFinished = false
loginManager.iCloudStatusWithCompletionHandler { (status, error) -> Void in

  if (isTestFinished) {
    return
  }

  expectation.fulfill()
  XCTAssertTrue(status.isEqualToString("NoAccount"), "Status is Available")

}

waitForExpectationsWithTimeout(5, { error in
  isTestFinished = true
  XCTAssertNil(error, "Error")
})

But i am getting error while compiling the code

:0: error: cannot override 'init' which has been marked unavailable

What is best way I am using mock object to test my LoginManager class ?

Thanks



Solution 1:[1]

I have an idea for this problem. But I'm not good at swift so I provide my code in Objective-C Firstly , try create CKContainerMock in your testClass like this:

@interface CKContainerMock : CKContainer
@property (nonatomic, copy) void (^mCompletionHandlerMock)(CKAccountStatus accountStatus,NSError *error);
- (void)accountStatusWithCompletionHandler:(void (^)(CKAccountStatus accountStatus, NSError *error))completionHandler
@end

@implementation CKContainerMock
- (void)accountStatusWithCompletionHandler:(void (^)(CKAccountStatus accountStatus, NSError *error))completionHandler {
  self.mCompletionHandlerMock = completionHandler;
}
@end

In your testFunction
Example:
Success case:

 -(void) testCKContainerResultSucces {
       LoginManager loginManager = [LoginManager sharedInstance];
       CKContainerMock *ckContainerMock = [[CKContainerMock alloc] init];
       [loginManager setCKContainer:ckContainerMock]; // Change your ckContainer object to mockObject.
       [loginManager iCloudStatusWithCompletionHandler:^(CKAccountStatus accountStatus,NSError *error) {
          XCAssert(accountStatus == CKAccountStatusAvailable);
        }];
       loginManager.ckContainer.mCompletionHandlerMock(CKAccountStatusAvailable,nil);
    }

Error case:

-(void) testCKContainerResultError {
   LoginManager loginManager = [LoginManager sharedInstance];
   CKContainerMock *ckContainerMock = [[CKContainerMock alloc] init];
   [loginManager setCKContainer:ckContainerMock]; //Change your ckContainer object to mockObject.
   [loginManager iCloudStatusWithCompletionHandler:^(CKAccountStatus accountStatus,NSError *error) {
      XCAssertNotNil(error);
    }];
   loginManager.ckContainer.mCompletionHandlerMock(nil,[NSError errorWithDomain:NSPOSIXErrorDomain code:22 userInfo:nil]);
}

Greate mock example for you

Hope this help.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community