I am using OCMock 3 to unit test my iOS project.
I use dispatch_once() created a singleton class MyManager :
#implementation MyManager
+ (id)sharedInstance {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
I have a method in School class which uses the above singleton:
#implementation School
...
- (void) createLecture {
MyManager *mgr = [MyManager sharedInstance];
[mgr checkLectures];
...
}
#end
Now, I want to unit test this method, I use a partial mock of MyManager:
- (void) testCreateLecture {
// create a partially mocked instance of MyManager
id partialMockMgr = [OCMockObject partialMockForObject:[MyManager sharedInstance]];
// run method to test
[schoolToTest createLecture];
...
}
- (void)tearDown {
// I want to set the singleton instance to nil, how to?
[super tearDown];
}
In tearDown phase, I want to set the singleton instance to nil so that the following test case could start from clean state.
I know on internet, some people suggest to move the static MyManager *sharedMyManager outside the +(id)sharedInstance method. But I would like to ask, is there any way to set the instance to nil without moving it outside +(id)sharedInstance method? (Any solution like java reflection?)
You can't achieve what you want with a local static variable. Block-scoped statics are only visible inside their lexical context.
We do this by making the singleton instance a static variable scoped to the class implementation and adding a mutator to override it. Generally that mutator is only called by tests.
#implementation MyManager
static MyManager *_sharedInstance = nil;
static dispatch_once_t once_token = 0;
+(instancetype)sharedInstance {
dispatch_once(&once_token, ^{
if (_sharedInstance == nil) {
_sharedInstance = [[MyManager alloc] init];
}
});
return _sharedInstance;
}
+(void)setSharedInstance:(MyManager *)instance {
once_token = 0; // resets the once_token so dispatch_once will run again
_sharedInstance = instance;
}
#end
Then in your unit test:
// we can replace it with a mock object
id mockManager = [OCMockObject mockForClass:[MyManager class]];
[MyManager setSharedInstance:mockManager];
// we can reset it so that it returns the actual MyManager
[MyManager setSharedInstance:nil];
This also works with partial mocks, as in your example:
id mockMyManager = [OCMockObject partialMockForObject:[MyManager sharedInstance]];
[[mockMyManager expect] checkLectures];
[MyManager setSharedInstance:mockMyManager];
[schoolToTest createLecture];
[mockMyManager verify];
[mockMyManager stopMocking];
// reset it so that it returns the actual MyManager
[MyManager setSharedInstance:nil];
Here's a full breakdown of the approach.
The answer is no, because you use dispatch_once(&onceToken, ^{ so even if you added another method which could reset the variable to nil you'd never be able to initialise it again.
So you already have one solution and the best solution is to not access the singleton directly (use dependency injection instead).
It is an easier way to solute your issue.
Your class have a singleton. you can add a method that is destroy this class instance. So when you call shareManager method again , it will create a new instance.
Such as:
static MyManager *sharedMyManager = nil;
+ (void)destroy
{
sharedMyManager = nil;
}
As others have stated, what you should really do is refactor your code to use dependency injection. This means that if the School class needs a MyManager instance to operate, then it should have an initWithManager:(MyManager *)manager method which should be the designated initializer. Or if the MyManager is only needed in this particular method, it should be a method parameter, e.g. createLectureWithManager:(MyManager *)manager.
Then in your tests, you could just do School *schoolToTest = [[School alloc] initWithManager:[[MyManager alloc] init]], and each test would have a new MyManager instance. You could drop the singleton pattern entirely, removing the sharedInstance method on MyManager and your application's logic would be responsible to ensure that there is only one instance that you pass around.
But sometimes, you have to work with legacy code that you can't just refactor. In these cases, you need to stub the class method. That is, you need to replace the implementation of -[MyManager sharedInstance] with an implementation that returns [[MyManager alloc] init]. This can be accomplished using the runtime to swizzle the class method, which would be the equivalent of Java reflection that you are looking for. See this for an example of how to use the runtime.
You can also do it with OCMock, which uses the runtime behind the scenes, just like mocking frameworks in Java are based on the reflection API :
MyManager *testManager = [[MyManager alloc] init];
id mock = [[OCMockObject mockForClass:[MyManager class]];
[[[mock stub] andReturn:testManager] sharedInstance];
If you don't want to refactor your code for easier unit testing then there is another solution (not perfect but works):
Create a local property of MyManager type
In setUp instantiate the property from above and swizzle the sharedInstance method with your local method (e.g. swizzle_sharedInstance)
Inside the swizzle_sharedInstance return the local property
In tearDown swizzle back to original sharedInstance and nullify the local property
I suggest a little bit different approach. You can create a mock of your sharedInstance using OCMock:
id myManagerMock = OCMClassMock([MyManager class]);
OCMStub([myManagerMock sharedManager]).andReturn(myManagerMock);
Now School implementation will use myManagerMock object, and you can stub this object to return anything you want under you test case. For example:
OCMStub([myManagerMock someMethodThatReturnsBoolean]).andReturn(YES);
It's important that after your tests, you will perform cleaning of your mock object by calling (at the end of your test method or in -tearDown):
[myManagerMock stopMocking];
Related
I am new in OCMock.
I use dispatch_once() created a singleton class MyManager :
#implementation MyManager
+ (id)sharedInstance {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
I have a method in School class which uses the above singleton:
#implementation School
...
- (void) createLecture {
MyManager *mgr = [MyManager sharedInstance];
[mgr checkLectures];
...
}
#end
Now, I want to unit test this method, I use a partial mock of MyManager:
- (void) testCreateLecture {
// create a partially mocked instance of MyManager
id partialMockMgr = [OCMockObject partialMockForObject:[MyManager sharedInstance]];
// run method to test
[schoolToTest createLecture];
...
}
I noticed that with OCMock, after I created the partial mock of my singleton MyManager instance, when run my method under test, it automatically use the partially mocked instance.
This is a bit weird to me, since in my test case above, I only created the partial mock of MyManager instance without injecting it to MyManager class,
how does OCMock automatically force the code under test use this mocked instance when [MyManager sharedInstance] is called in the code under test ? Could someone explain to me this?
partialMockForObject mocks the object you are passing to it.
In this case you are mocking the singleton (shared) object. You don't have to inject anything because sharedInstance is always returning the same object, now mocked. It is still the same reference.
Imagine partial mocking as a simple mutation of the passed object, it doesn't create a new instance so you don't have to inject it in this specific case.
Partial Mocks are pretty cool. Behind the scenes, OCMock subclasses the class you are mocking, and any method that you stub is updated in the partial mock subclass. So all references to your mocked class will now default to the subclass (mocked implementation) instead of the superclass (your implementation). There's a good explanation in the reference on this as well.
The title is the question's formulation - i.e. what are the patterns and anti-patterns of +initialize and +load class methods overriding?
Have you met particular examples? If yes - please describe.
P.S. There was some good Q&A on +load and +initialize here on StackOverflow but no one tells about the practical interest of these methods. Mechanisms were discussed.
+load is useful for setting up stuff needed for categories because all the +load methods are guaranteed to be called once each when the binary is loaded (even if there are multiple +load methods for the same class, which normally would replace one another). Inheritance is actually irrelevant to its functioning.
I almost never use +load, but +initialize is useful for all sorts of things... setting up static variables, dynamically loading libraries for plugin architectures... anything you want to do one time like printing version info, setting up a global instance to do something specialized, like for logging, crash reporter, signal handler, etc...
edit:
to prevent multiple initialize calls from messing stuff up (which happens to superclasses when the child class is used after a superclass): you can make it reentrant (this is a common pattern):
+(void) initialize {
static BOOL inited = NO;
if(!inited)
{
/*dostuff*/
inited=YES;
}
}
A good use of the load method is to initialize global variables that can't be initialized at compile-time.
Here is a made up example:
SomeClass.h
extern NSString *SomeGlobalConstant;
// Followed by some class interface stuff
SomeClass.m
#import "SomeClass.h"
NSString *SomeGlobalConstant = nil;
static NSArray *someFileStaticArray = nil;
#implementation SomeClass
+ (void)load {
if (self == [SomeClass class]) {
SomeGlobalConstant = #"SomeAppropriateValue";
someFileStaticArray = #[ #"A", #"B", #"C" ];
}
}
// and the rest of the class implementation
#end
Another possible use of +initialize is for Method Swizzling. Which you shouldn't really use unless you're sure you know what you're doing. Read this SO question for more details.
It allows you to substitute an existing method implementation with your own, and still be able to call the original one. For instance, for faking NSDate in unit tests you could write something like this (note, that there are other ways to do this (OCMock, etc.), this is just an example). This code allows you to set a program-wide fake NSDate, which will be returned whenever [NSDate date] is called. And if no fake date is set, then the original implementation is used.
#import "NSDate+UnitTest.h"
#import "MethodSwizzling.h"
#implementation NSDate(UnitTest)
static NSDate *fakeCurrentDate = nil;
+(void)setFakeCurrentDate:(NSDate *)date
{
fakeCurrentDate = date;
}
+(NSDate *)fakeCurrentDate
{
if (fakeCurrentDate) {
return fakeCurrentDate;
}
else {
NSDate *result = [self fakeCurrentDate];
return result;
}
}
+(void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(#"Swizzling...");
SwizzleClassMethod([self class], #selector(date), #selector(fakeCurrentDate));
});
}
#end
//MethodSwizzling.m:
void SwizzleMethod(Class c, SEL orig, SEL new, BOOL isClassMethod) {
NSLog(#"Swizzling %# method %# of class %# with fake selector %#.",
(isClassMethod ? #"a class" : #"an instance"),
NSStringFromSelector(orig),
NSStringFromClass(c),
NSStringFromSelector(new));
Method origMethod = isClassMethod ? class_getClassMethod(c, orig) : class_getInstanceMethod(c, orig);
Method newMethod = isClassMethod ? class_getClassMethod(c, new) : class_getInstanceMethod(c, new);
method_exchangeImplementations(origMethod, newMethod);
//Actually, it's better to do it using C-functions instead of Obj-C methods and
//methos_setImplementation instead of method_exchangeImplementation, but since this
//is not an open-source project and these components aren't going to be used by other people,
//it's fine. The problem is that method_exchangeImplementations will mess things up if
//the implementation relies on a fact that the selector passed as a _cmd parameter
//matches the function name.
//More about it: http://blog.newrelic.com/2014/04/16/right-way-to-swizzle/
}
void SwizzleClassMethod(Class c, SEL orig, SEL new) {
SwizzleMethod(c, orig, new, YES);
}
void SwizzleInstanceMethod(Class c, SEL orig, SEL new) {
SwizzleMethod(c, orig, new, NO);
}
I havea Utility class that uses class methods. I am trying to refer to self in the class method but can't. I was wondering how would I declare the following in a class method:
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
self.window it says member reference type struct objc_class *' is a pointer; maybe you meant to use '->'
Another problem that relates to not being able to call self is how would I refer to a declared #property in my .h in a class method in my .m.
Here is my class method:
.m
+ (void)showHUD
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
//I would preferably like to call my property here instead
}
.h
#property (nonatomic) MRProgress * mrProgress;
The whole point of a class method is that it is not part of a specific instance. Inside of a class method, self is the class.
If you need to be tied to a specific instance, then it should be an instance method. If you want a static method that accesses a specific instance, then pass that instance (self) to it (though it's hard to imagine many cases where that makes sense).
In the above example, showHUD should be an instance method almost certainly. If that doesn't make sense for some reason, then it should be:
+ (void)showHUDForWindow:(UIWindow *)window;
You can then call it as showHUDForWindow:self.window and use that as needed.
You can use a singleton pattern. Singleton pattern assumes that the only instance of your class exists. Since it's the only instance, you can then use it from class methods.
Example implementation:
+ (MyClass*)sharedInstance {
static dispatch_once_t once;
static MyClass *sharedMyClass;
dispatch_once(&once, ^ {
sharedMyClass = [[self alloc] init];
});
return sharedMyClass;
}
Then you can access the shared instance via [MyClass sharedInstance], for example:
+ (void)doSomethingCool {
[[self sharedMyClass] doSomething];
}
I am making a singleton class for my use . I have seen code for singleton class is like this:
//First Example
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
//Second Example
static SingletonSample *sharedObject;
+ (SingletonSample*)sharedInstance {
if (sharedObject == nil) {
sharedObject = [[super allocWithZone:NULL] init];
}
return sharedObject;
}
The seconds seems fine and understandable. But i am confused in First example where sharedMyManager is set to nil each time and also there is a allocation of shared manager each time, my doubt is that how will first example return the same reference of the class(Singleton).
Thanks.
First of all when static is declared with in function, it is declared only once. So, the line
static MyManager *sharedMyManager = nil;
Will be executed only once when the function gets called for first time.
In the next line when you use dispath_once, it will be executed for only once. So the creation of sharedMyManager will be done once only. So, thats a perfect way to create a single ton class.
As it's static it will initially be set to nil, but in subsequent calls the value will remain to whatever you have set it to in previous calls.
The first example is better as it is thread safe. The second example doesn't even initialise sharedObject which is dangerous (I don't believe there is a guarantee that global variables are initialised to zero).
sharedMyManager is set to nil each time
static variables are set only once.
there is a allocation of shared manager each time
You use dispatch_once, so it's incorrect too.
Read about dispatch_once here.
And using GCD is faster and thread safe.
I am using a singleton that I have setup that I am using to both preload and access my audio files (both sfx and music) I started out running [[FGAudio sharedInstance] preload]; from the AppDelegate but was concerned about having to remember to call preload before using the singleton. My question is to make things automatic, can I access a method on the singleton to do my setup and preload in init, or is it not wise to access a method init as things are still starting up?
+ (FGAudio *)sharedInstance {
static FGAudio *sharedAudio = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAudio = [[FGAudio alloc]init];
});
return sharedAudio;
}
.
- (id)init {
self = [super init];
if(self) {
[self preload];
}
return self;
}
+ (FGAudio *)sharedInstance {
static FGAudio *sharedAudio = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAudio = [[FGAudio alloc]init];
[sharedAudio preload];
});
return sharedAudio;
}
Referencing the method from init isn't bad if you can guarantee that subclasses won't mess with it or the objects it relies upon and in the future you won't mess up the preloading period by requiring objects that get inited after you call preload. If you use the above snippet you don't even have to worry about any of that and you also get a preloaded singleton.
Calling a method from the init method?
"Yes. Just be very careful (your object may not have been fully initialised, it shouldn't use accessor methods so as to comply with the previous restriction, et cetera)"