Swift Singleton Init在XCTest中调用了两次

时间:2014-11-27 14:02:47

标签: ios objective-c swift singleton

使用Swift时,单个初始化程序在运行XCTest单元测试时称为两次

没有Objective-C的问题,init()方法只按预期调用一次。

以下是如何构建两个测试项目:

的Objective-C

Singleton Class

使用测试创建一个空的Objective-C项目。添加以下裸机单例:

#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

在应用程序委托中添加对单例的调用,如下所示:

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

XCTestCase

还要对生成的测试类添加对单例的调用:

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

结果

如果向单例的init方法添加断点并运行测试,断点将只按一次,如预期的那样。

夫特

现在创建一个新的Swift项目并做同样的事情。

的Singleton

创建单例,将测试目标添加到其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")
}

结果

这一次,如果你向单例的init方法添加一个断点并运行测试,那么断点将首先从app委托中被击中两次,,然后从测试用例中,即你将有两个单身实例。

我错过了什么吗?

1 个答案:

答案 0 :(得分:8)

由于应用程序模块和测试模块是分离的模块,因此当您将Singleton.swift文件添加到测试目标成员时,YourApp.SingletonYourAppTest.Singleton不是同一类。这就是init两次调用的原因。

而不是那样,您应该在测试文件中import主模块:

import YourAppName

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

并且您的Singleton类必须声明为public。见Swift, access modifiers and unit testing

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)")
    }
}

不要忘记从测试目标成员资格中删除Singleton.swift