Swift Singleton Init called twice in XCTest

With Swift, the parser is called twice during the execution of unit tests of XCTest.

There is no problem with Objective-C, but the init () method is called only once, as expected.

Here's how to build two test projects:

Objective-c

Singleton class

Create an empty Objective-C project with tests. Add the following bare bone singleton:

#import "Singleton.h" @implementation Singleton + (Singleton *)sharedInstance { static Singleton *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[Singleton alloc] init]; // Do any other initialisation stuff here }); return sharedInstance; } - (instancetype)init { self = [super init]; if (self) { NSLog(@"%@", self); } return self; } @end 

Appdelegate

In application deletes, add a call to singleton, for example:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. [Singleton sharedInstance]; return YES; } 

XCTestCase

Also add a singleton call to the generated test class:

 - (void)testExample { [Singleton sharedInstance]; // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } 

results

If you add a breakpoint to the singleton init method and run the tests, the breakpoint will only be deleted once , as expected.

Swift

Now create a new Swift project and do the same.

Singleton

Create a singleton, add a test target to Target Memberships

 class Singleton { class var sharedInstance : Singleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! } init() { NSLog("\(self)") } } 

Appdelegate

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. Singleton.sharedInstance return true } 

XCTestCase

 func testExample() { // This is an example of a functional test case. Singleton.sharedInstance XCTAssert(true, "Pass") } 

results

This time, if you add a breakpoint to the singleton init method and run the tests, the breakpoint will be deleted twice, first from the application delegate and then from the test case, i.e. you will have two singleton instances.

Did I miss something?

+7
ios objective-c singleton swift
source share
1 answer

Since the application module and the testing module are separate modules, adding the Singleton.swift file to check the target member YourApp.Singleton and YourAppTest.Singleton are not the same class. This is why init is called twice.

Instead, you should import your main module in a test file:

 import YourAppName func testExample() { // This is an example of a functional test case. Singleton.sharedInstance XCTAssert(true, "Pass") } 

and your Singleton class should be declared as public . see Swift, access modifiers and unit tests

 public class Singleton { public class var sharedInstance : Singleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! } init() { NSLog("\(self)") } } 

Remember to remove Singleton.swift from the target destination.

+8
source share

All Articles