I often find in my iPhone Objective-C unit tests that I want stub out a class method, e.g. NSUrlConnection's +sendSynchronousRequest:returningResponse:error: method.
Simplified example:
- (void)testClassMock
{
id mock = [OCMockObject mockForClass:[NSURLConnection class]];
[[[mock stub] andReturn:nil] sendSynchronousRequest:nil returningResponse:nil error:nil];
}
When running this, I get:
Test Case '-[WorklistTest testClassMock]' started.
Unknown.m:0: error: -[WorklistTest testClassMock] : *** -[NSProxy doesNotRecognizeSelector:sendSynchronousRequest:returningResponse:error:] called!
Test Case '-[WorklistTest testClassMock]' failed (0.000 seconds).
I've had a really hard time finding any documentation on this, but I assume that class methods aren't supported by OCMock.
I found this tip after a lot of Googling. It works, but is very cumbersome:
http://thom.org.uk/2009/05/09/mocking-class-methods-in-objective-c/
Is there anyway to do this within OCMock? Or can someone think of a clever OCMock category object that could be written to accomplish this sort of thing?
Update for OCMock 3
OCMock has modernized its syntax for supporting class method stubbing:
id classMock = OCMClassMock([SomeClass class]);
OCMStub(ClassMethod([classMock aMethod])).andReturn(aValue);
Update
OCMock now supports class method stubbing out of the box. The OP's code should now work as posted. If there is an instance method with the same name as the class method, the syntax is:
[[[[mock stub] classMethod] andReturn:aValue] aMethod]
See OCMock's Features.
Original Answer
Sample code following Barry Wark's answer.
The fake class, just stubbing connectionWithRequest:delegate:
#interface FakeNSURLConnection : NSURLConnection
+ (id)sharedInstance;
+ (void)setSharedInstance:(id)sharedInstance;
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
#end
#implementation FakeNSURLConnection
static id _sharedInstance;
+ (id)sharedInstance { if (!_sharedInstance) { _sharedInstance = [self init]; } return _sharedInstance; }
+ (void)setSharedInstance:(id)sharedInstance { _sharedInstance = sharedInstance; }
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate {
return [FakeNSURLConnection.sharedInstance connectionWithRequest:request delegate:delegate];
}
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate { return nil; }
#end
Switching to and from the mock:
{
...
// Create the mock and swap it in
id nsurlConnectionMock = [OCMockObject niceMockForClass:FakeNSURLConnection.class];
[FakeNSURLConnection setSharedInstance:nsurlConnectionMock];
Method urlOriginalMethod = class_getClassMethod(NSURLConnection.class, #selector(connectionWithRequest:delegate:));
Method urlNewMethod = class_getClassMethod(FakeNSURLConnection.class, #selector(connectionWithRequest:delegate:));
method_exchangeImplementations(urlOriginalMethod, urlNewMethod);
[[nsurlConnectionMock expect] connectionWithRequest:OCMOCK_ANY delegate:OCMOCK_ANY];
...
// Make the call which will do the connectionWithRequest:delegate call
...
// Verify
[nsurlConnectionMock verify];
// Unmock
method_exchangeImplementations(urlNewMethod, urlOriginalMethod);
}
Coming from the world of Ruby, I understand exactly what you're trying to accomplish. Apparently, you were literally three hours ahead of me trying to do exactly the same thing today (time zone thing? :-).
Anyway, I believe that this is not supported in the way one would desire in OCMock because stubbing a class method needs to literally reach into the class and changes its method implementation regardless of when, where, or who calls the method. This is in contrast to what OCMock seems to do which is to provide you a proxy object that you manipulate and otherwise operate on directly and in lieu of a "real" object of the specified class.
For example, it seems reasonable to want to stub NSURLConnection +sendSynchronousRequest:returningResponse:error: method. However, it is typical that the use of this call within our code is somewhat buried, thus making it very awkward to parameterize it and swap in a mock object for the NSURLConnection class.
For this reason, I think the "method swizzling" approach you've discovered, while not sexy, is exactly what you want to do for stubbing class methods. To say it's very cumbersome seems extreme -- how about we agree it's "inelegant" and maybe not as convenient as OCMock makes life for us. Nevertheless, it's a pretty concise solution to the problem.
Here is a nice 'gist' with a swizzle implementation for class methods: https://gist.github.com/314009
If you modify your method under test to take a parameter which injects the class of the NSURLConnection, then it's relatively easy to pass in a mock that responds to the given selector (you may have to create a dummy class in your test module which has the selector as an instance method and mock that class). Without this injection, you're using a class method, essentially using NSURLConnection (the class) as a singleton and hence have fallen into the anti-pattern of using singleton objects and the testability of your code has suffered.
Link to the blogpost in the question and RefuX gist inspired me to come up with block enabled implementation of their ideas: https://gist.github.com/1038034
Related
What I want to do is cause another save anytime saveInBackgroundWithBlock is called in my app. Im doing this to create a "log" of everything that changes and who changed it. I looked into the PFObject.h but I am not sure how to properly write this in Obj-C or where else/how I could do this other than going through and adding it to every single instance. Is this a good way to do it? Or should I stick it out and use the harder way?
- (void)saveInBackgroundWithBlock:(nullable PFBooleanResultBlock)block;
you have multiple ways in order to achieve this kind of functionality:
Create Util class which receive PFObject and PFBooleanResultBlock as parameters this Util class will execute a call to saveInBackgroundWithBlock inside the callback you can implement the additional save that you need. at the end your Util class should look like the following:
#interface ParseUtils : NSObject
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block;
#end
#implementation ParseUtils
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block {
// if the object is nil or it was not changed return
if (!object || !object.isDirty) return;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
// if no error occured
if (!error){
// HERE YOU SHOULD CALL YOUR ADDITIONAL SAVE...
}
// handle the callback to the calling class
if (block){
block(succeeded,error);
}
}];
}
#end
Another option is to do the same but with singleton (if you created some REST Client singleton for your project)
Another nice option is to create category on top of the PFObject and there to create a method which do exactly the same like the method that of the util
There are more options but i think that it's enough..
if you want to do it as quick as possible use the utilities. if you want to do it with best architecture then go with the category.
working on xcode I realized that if I create a non-void method, I call it from a class / method, the result is processed optimally only if the action is immediate. I tried to do a test by inserting a delay and I realized that it no longer works.
I will write down here the example that I created:
Class A
//--------------------CLASS A
- (void)viewDidLoad {
[super viewDidLoad];
i = 0;
Class *classB = [[Class alloc] init];
i = [classB method1];
[self performSelector:#selector(method3) withObject:NULL afterDelay:1.8];
}
-(void)method3 {
NSLog(#"i = %i",i); // i = 0
}
Class B
//--------------------CLASS B
-(int)method1 {
[self performSelector:#selector(method2) withObject:NULL afterDelay:1];
return a;
}
-(void)method2 {
a = 800;
}
Obviously my problem is not something so trivial but I tried to make it easy to get an answer as thoroughly as possible, I was advised to use modal methods but I don't think that's the solution I was looking for.
What could I do to solve this?!
What you really need is a better understanding of asynchronous methods. In your method1, the variable a is never altered -- all you are doing is scheduling method2 to be called in the future and then returning the current state of variable a.
In Objective-C, there are a few different ways you can solve this problem. People most commonly use protocols and delegates to solve this issue. Here is a basic intro to protocols and delegates. Basically, you would want your class A object to be a delegate of your class B object. You could also use NSNotifications or blocks, although you should probably understand the usage of protocols and delegates (they are very important in Objective-C) before moving on to notifications and blocks.
What could I do to solve this?!
Where do you want to return the value to? In your example, method1 will complete long before method2 is ever invoked. If you want to preserve the value calculated by method2, you'll typically have that method store the value in one of ClassB's instance variables and possibly call some other method to continue processing.
If you really need method1 to return the result from method2, you'll need to call it synchronously (i.e. without -performSelector:withObject:afterDelay:). In this case, consider a) why you need the delay at all; and b) if you should perhaps be calling method1 after a delay instead of method2.
We'll be able to provide much better help if you can explain what the real-world problem that you're trying to solve is.
I have a singleton class that is instantiated as follows:
#import "FavoritesManager.h"
static FavoritesManager *sharedFavoritesManager = nil;
#implementation FavoritesManager
+ (id)sharedManager {
#synchronized(self) {
if (sharedFavoritesManager == nil) {
sharedFavoritesManager = [[self alloc] init];
}
}
return self;
}
This returns an object, but for some reason it will only respond to class methods. If I call a instance method I get
+[FavoritesManager testMethod]: unrecognized selector sent to class 0x59198
For what it's worth, this is what testMethod looks like:
- (void)testMethod {
NSLog(#"Test");
}
and I'm absolutely positive it's declared in the interface. I've used this exact code in other classes and it works like a charm, so I don't really understand what the problem is here. One thing that is suspicious is the plus sign in +[FavoritesManager testMethod], but I can't explain it. Any ideas?
EDIT: I was confusing public/private and class/method terminology. Thanks to everyone who pointed that out.
If you want to call testMethod from another class method then you need:
+ (void)testMethod {
NSLog(#"Test");
}
The reason is that if you call a class method then there's no instance, so nothing on which to call instance methods. But probably you want to call:
[[FavoritesManager sharedManager] testMethod];
Which means 'get the shared instance, then call testMethod on it'. Thinking as I type, you might also like to add:
+ (void)forwardInvocation:(NSInvocation *)anInvocation
{
id sharedManager = [self sharedManager];
if ([sharedManager respondsToSelector:
[anInvocation selector]])
[anInvocation invokeWithTarget:sharedManager];
else
[super forwardInvocation:anInvocation];
}
Which is the Objective-C means for message forwarding. So if the metaclass FavoritesManager receives a message it can't respond to, it lets its shared manager instance have a go. That means that:
[FavoritesManager testMethod];
Becomes functionally equivalent to (though a little slower than):
[[FavoritesManager sharedManager] testMethod];
Providing that you haven't implemented a class method in addition to an instance method. You can learn more about message forwarding in Apple's official documentation.
The error indicates that you're sending the message testMethod to the class, rather than an instance.
The reason for this is that your sharedManager method is incorrect. You are currently returning self, which, in this class method, is the class itself. This means that when you write [[FavoritesManager sharedManger] testMethod] you end up sending testMethod to the class. Since testMethod isn't a class method, you get an error.
You should have return sharedFavoritesManager; at the end of sharedManager, not return self;. The latter is correct only in instance method initializers.
Also, as dbrajkovic commented, you seem to be confused about public/private and class/instance methods. Strictly, ObjC has no private methods. You can hide the declaration, which will cause a compiler warning, but the message will still be sent and the method will be called. The + and - distinguish class methods from instance methods; the distinction is which kind of object you send a message to. Info here: What is the difference between class and instance methods?
The error is right you must be calling [FavoritesManager testMethod] which means you're trying to call a class method. I believe you want [[FavoritesManager sharedManager] testMethod];
+ at the start of a method declaration means that it's a class method, - means that it's an instance method. Do this:
+(void)testMethod {
NSLog(#"Test");
}
If you want to invoke testMethod on your sharedManager, then keep the testMethod declaration as you have it and instead change your invocation to
[[FavoritesManager sharedFavoritesManager] testMethod];
Either will work, and choosing between the two is a matter of app design.
Instead try
[[FavoritesManager sharedFavoritesManager] testMethod];
there are no priavte methods in obj-c.
But anyway on a singleton you are always calling from the outside of the class, so only declare "public methods". for detailed help post your code.
Call your singleton instance:
[[ FavoritesManager sharedManager] testMethod];
What is the difference between class and instance methods in Objective-C and when should I use each of them?
Using the tired old Car analogy...
Think of a Class like it is a factory that makes Instances of the class. For example, you might have a Car class and you might declare a method like:
+ carWithColor: (NSColor *) aColor;
And that method would then create a new Car instance, set the color, and return it:
+ carWithColor: (NSColor *) aColor
{
Car *aCar = [[[self alloc] init] autorelease];
[aCar paintWithColor: aColor];
return aCar;
}
Now, that Car class would then declare an instance method that allows the car to be painted. Why an instance method? Because every car can have a different color (and the color of the car would likely be stored in an instance variable).
- (void) paintWithColor: (NSColor *) aColor
{
... do your paint stuff here ...
}
This is explained in the Objects, Classes, and Messaging section of the Objective-C documentation.
This is an old post, but since it comes up first in a Google search I thought I'd add to it.
I'm not going to talk about class methods used as factory methods. I'd like to talk about their use in utility methods. You can/should use class methods for utility methods that are independent of state. What does this mean? Well, for instance, if you're formatting a date the same way for all instances, that's a utility method that should be a class method. Think of the utility method like a screw driver. You don't need to make a new instance of the screw driver every time you want to do something with it. The screw driver remains constant. So, for instance, I have a class that includes a private method that generates a string of emDashes used for displaying to the view. This method is not dependent on state and hence will not vary by instance. Think of class utility methods like constants.
+ (NSString *)emDashString {
return #" \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014 \u2014";
}
You can call this method generically within the class (it's private in my example) like this:
NSString *string = [[self class] emDashString ];
I've deliberately chosen a bit of a trivial example to drive the point home. You would only bother making this a class utility method if you're going to need this string more than once in your class. Notice that instead of referring to the class by name I call it generically with [self class] since this is called internally. If it's exposed and you want to call it from another class then refer to it by the class name as usual.
Instance methods do things with instances of a class:
NSString *myString;
myString = [[[NSString alloc] initWithString:#"Hello, world."] autorelease];
NSLog (#"myString's length: %u", [myString length]); // instance method
Class methods can do class-specific things without relying on an object instance, often returning an instance of the class, or some other class-specific result:
NSLog (#"%#", [NSString stringWithString:#"Hello, world."]); // class method
I think it may be rare to see class methods that do not return something.
You don't need to implement both. Either option is available to you as you design your class.
An instance method can operate on an instance of the class. This can get or set a property, or cause behavior you only want that instance to perform. You need to actually have an instance to use it. These can either use or change the state of the instance.
// Notional instance methods
myHouse.color = blueColor;
[myCar accelerate];
speed = myCar.speed;
A class method operates on the notion that the class exists. It can be used to create an instance, or perform a calculation that doesn't depend on having an instance. You might have a class for custom math helper, that essentially contains functions.
// Notional class method uses
myString = [NSString stringWithFormat:#"&f", floatToConvert];
myResult = [MyMathHelper MyFunctionWithInput:myInput];
Class method signatures are prefixed with +, instance methods with - so in your header file declarations would look something like this:
-(void)setAllThings:(NSArray*)things; //instance method
+(void)setAllClassThings:(NSArray*)things; //class method
And of course the same rules apply when you define the methods in the .m file.
I’m sure this is a simple one, but it’s been elusive so far, and I’m stumped ...
How do I declare an Ivar so that it’s accessible from ALL Classes in a project?
[Don’t know if it matters, but the ivar in question is (an instance of) my Model class, whose data needs to be accessible to various view controllers.]
Best as I can tell from "The Scope of Instance Variables” in The Objective-C 2.0 Programming Language
... this would be by using the “#public” directive.
So I’ve tried this in the #interface block where the ivar is declared:
#interface ...
...
#public
ModelClass *theModel;
#end
... But when I try to refer to “theModel” in a different class, the compiler doesn’t auto-complete, and when I type it in anyway, the compiler shows:
“Error: ‘theModel’ undeclared (first use in this function)”.
I assume this is a question of Scope, and that I haven’t made the ivar available appropriately, but how? Somehow I need to access this, or make its pointer available somehow.
Any ideas would be VERY much appreciated. Many thanks!
Perhaps you forgot to put the instance variable inside the braces of the class where all instance variable declarations go?
#interface Foo : NSObject {
// other instance variable declarations
#public
ModelClass *theModel;
}
// method and property declarations
#end
Also, can you show us the code of how you are trying to access the instance variable from elsewhere? The proper syntax should be:
myFooInstance->theModel
where myFooInstance is a value of type "Foo *"
I make properties available to all views managed by a Tab Bar via a singleton representing my data model. This is efficient and allows all Views access to the data (as well as any other application elements. Creating the singleton is straightforward (there are a ton of examples on S.O.). The you just request the instance and get the property values you need.
Here is a framework fro creating the Singleton. The key points are the static instance and the fact that you do the initialization as [[self alloc] init];. This will ensure the object gets cleaned up correctly. All the methods at the bottom of the class are standard from the SDK Docs to make sure release calls are ignored (because the object is shared globally).
Singleton Boilerplate (ApplicationSettings.m):
static ApplicationSettings *sharedApplicationSettings = nil;
+ (ApplicationSettings*) getSharedApplicationSettings
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedApplicationSettings;
}
+ (id)allocWithZone:(NSZone *)zone
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
sharedApplicationSettings = [super allocWithZone:zone];
return sharedApplicationSettings; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
You cannot access iVars from any other class.
You have to declare a getter/setter method to change or view a variable from another class - what you are really looking for are properties, that make it easier to define and access these getter/setter methods.
In your example above, you'd have the property defined just after the block that defines the local variable in the header file:
#property (nonatomic, retain) ModelClass *theModel;
In the implementation file you'd have the getter/setter created with the #synthesize statement just after the #implementation line:
#synthesize theModel;
Then if you have an instance of your class created, you access the class instance variable like so:
myInstance.theModel = [[[ModelClass alloc] init] autorelease];
The reason #public & #private are in there are to define visibility for subclasses (which, being extensions of that class type also get all the class local variables defined by a superclass), not for any random class.
The standard Objective-C way of doing it is to have a class method that returns the ivar
In your .h file:
+ (id)defaultModel;
and in your .m file:
static ModelClass * defaultModelInstance;
#implementation ModelClass
+ (id)defaultModel {
if (!defaultModelInstance) {
defaultModelInstance = [[ModelClass alloc] init];
}
return defaultModelInstance;
}
#end
although this will need tweaking if you need a specific ivar instead of just "a ivar that's always the same"
this type of design is used by many Cocoa classes i.e. [NSWorkspace sharedWorkspace]
Think a C global variable.
Adding:
extern ModelClass* theModel;
after the #end in the header will make the variable visible anywhere you include the header.
In the ModelClass.cpp file add:
ModelClass* theModel;
before the class implementation.
The variable will still have a value of nil until you allocate and initialize it though and you will be resposible for ensuring that it gets deallocated at the correct time.
THANK YOU ALL for the very helpful discussion on this topic! Clearly there are several ways to approach things here, so this is a very useful assortment of techniques.
Just to let y'all know that in researching this issue further, I ran across a couple of other very helpful pages, listed below. They include mention of the NSNotificationCenter, which I hadn't heard of before; as well as the idea of the "dependency injection" design pattern.
The idea is to keep "low coupling"(1) between the classes, making the code more modular & better for unit testing.
And while the 'notification' pattern sounds like a great idea, in this case it may be a bit overkill, considering that I only need ONE instance of the data model throughout the run of the app, and it doesn't change throughout.
Finally, even though the "#public" compiler directive is well-documented in Apple's Obj-C guide(2), I later found a fascinating edict in a different doc stating that it shouldn't be used! Quoted from Apple's own Cocoa Fundamentals(3):
"Give the proper scope to your instance variables. Never scope a variable as #public as this violates the principle of encapsulation. ..."
(Strange that they don't mention this in their 'Objective-C 2.0' guide where the directive is actually explained.)
Anyway, here are a couple of other links I found to be full of some great insights as well. FYI:
S.O.: "What’s the best way to
communicate between
viewcontrollers?"(4) <<
CocoaWithLove: "Five approaches to
listening, observing and notifying in
Cocoa"(5)
CocoaWithLove: "Singletons,
AppDelegates and top-level data"(6)
Hope these help. Anyway, thank you all again!
Best,
rond
P.S. Yikes! It won't let me post more than one inline hyperlink, so I'm listing them here instead. Obviously, they’re all prefixed by “http://” ... :O
(1): en.wikipedia.org/wiki/Coupling_(computer_science)
(2): developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple%5Fref/doc/uid/TP30001163-CH12-TPXREF127
(3): developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/AddingBehaviortoaCocoaProgram/AddingBehaviorCocoa.html#//apple_ref/doc/uid/TP40002974-CH5-SW12
(4): stackoverflow.com/questions/569940/whats-the-best-way-to-communicate-between-viewcontrollers
(5): cocoawithlove.com/2008/06/five-approaches-to-listening-observing.html
(6): cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html