Reputation: 16186
I have a singleton class, and can't unit test their code.
I have test like:
Db *db = [[Db alloc] initWithName:@"sample.db"];
[db createDb];
STAssertEquals([db existDb],YES,@"The db is not created!");
But only work the first. When the second is executed, I always get "null" from the initWithName method. When I remove the singleton support code, all work as expected.
I could hack the testing (but I don't know how right now) but wonder if exist a "poper" way to deal with this.
The singleton is located here: http://code.google.com/p/chibiorm/source/browse/trunk/src/Db.m
Upvotes: 1
Views: 961
Reputation: 432
@implementation Singleton
+(nonnull instancetype)sharedInstance {
static Singleton *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
return self;
}
@end
Test Class - expose the init method to instantiate
@interface Singleton (Test)
- (nonnull instancetype)init;
@end
Upvotes: 0
Reputation: 180
The guy here has written what I would have written as the answer, which is use categories to provide differnet instances from your singleton methods as needed.
http://twobitlabs.com/2011/02/mocking-singletons-with-ocmock/
The other guys above who are all pontificating their opinions of "singletons are bad m'kay" should be ignored. The first thing I did when I switched to objective c was write an iOC library, which I never used because I realised that objective c is NOT java, so please ignore people who bleet on about about java dogma : it doens't always apply to objective c.
Upvotes: 0
Reputation: 1814
I think you shouldn't return nil on the second alloc but raise an exception. If you want to use a singleton you should not try to create two :).
However, if I decide to create a singleton my class looks like:
@implementation MySingleton
static id _instance = nil;
+ instance
{
if (_instance == nil) {
// alloc/init
_instance = [[self alloc] init];
…
}
return _instance;
}
…
@end
As you can see I am not enforcing that there may never be more than one instance. Instead I am using the convention to get the instance only with the instance method.
Upvotes: 0
Reputation: 20237
Maybe you could use the Factory pattern and create a factory that hands out only one instance (effectively your singleton). Then the implementation is not a singleton and you can unit test it to your hearts content.
The only drawback is that you are not protected by the language to create your own instance if you don't retrieve it from the factory. In C++ you may overcome this by making the constructor private and the factory and the unit test friends. I am not sure if Objective-C has a similar feature.
Upvotes: 0
Reputation: 683
Singletons are hard to unit test and are sometimes the result of poor design.
My recommendation would be to think hard about whether you really need a singleton in the first place.
Upvotes: 2