I am using OCMock on an objC project.
I have the following code:
DB_Account *Lena = [[DB_Account alloc] init];
Lena.niceName = #"Lena";
Lena.userId = #"Lena";
id mockStorageManager = OCMClassMock([V4_StorageManager class]);
[[[mockStorageManager stub] andReturn:Lena] getAccountByDBId:#1];
id mockDBNotificationManager = OCMClassMock([DBNotificationManager class]);
id partialV4DBNotificationManagerMock = OCMPartialMock([V4_DBNotificationManager manager]);
[[[mockDBNotificationManager stub] andReturn:(NotificationPolicy *)[NotificationPolicy Never]] getNotificationPolicy];
[[[partialV4DBNotificationManagerMock stub] andReturn:mockDBNotificationManager] dbNotificationManager];
BOOL shouldShow = [[V4_DBNotificationManager manager] showOnLoginExpired:Lena];
assertThatBool(shouldShow,is(isFalse()));
this code fails to compile on the following line:
[[[mockDBNotificationManager stub] andReturn:(NotificationPolicy *)[NotificationPolicy Never]] getNotificationPolicy];
with this error:
Error:(95, 5) multiple methods named 'getNotificationPolicy' found with mismatched result, parameter type or attributes
this method returns an object of type NotificationPolicy *, no other class implements or declares a method with this name.
What is wrong?
I had to do this to solve the problem
[(DBNotificationManager*)[[mockDBNotificationManager stub]
andReturn:[NotificationPolicy Never]] getNotificationPolicy];
Related
In Objective-C, how can I achieve something like this:
Class propertyClass = [self classForPropertyWithName:#"a_property"];
So you could break it into two steps.
Get a property by name (via -valueForKey:)
Get the class of the property (via -class)
Something like this maybe (note that this will fail for non object types):
Class propertyClass = [[self valueForKey:#"a_property"] class];
You should get the object with property named "key" using this method:
- (id)valueForKey:(NSString *)key
ie:
object = [valueForKey:#"propertyName"];
Then to get the class type you simply call the class method which is available for all object types except primitives.
Class classType = [object class];
I think the answer you are looking for is here. Code:
Class c = NSClassFromString(#"RootViewController");
Another option:
id object = // Fetch here;
Class c = [object class];
NSString *className = NSStringFromClass(c);
Documentation: link
I have a method I would like to test with OCMock but not sure how to do that. I need to mock
ExtClass which isn't defined as part of my code (external library):
+(NSString *)foo:(NSString *)param
{
ExtClass *ext = [[ExtClass alloc] initWithParam:param];
if ([ext someMethod])
return #"A";
else
return #"B";
}
Thanks in advance!
OCMock 2
id mock = [OCMockObject mockForClass:[ExtClass class]];
// We stub someMethod
BOOL returnedValue = YES;
[[[mock stub] andReturnValue:OCMOCK_VALUE(returnedValue)] someMethod];
// Here we stub the alloc class method **
[[[mock stub] andReturn:mock] alloc];
// And we stub initWithParam: passing the param we will pass to the method to test
NSString *param = #"someParam";
[[[mock stub] andReturn:mock] initWithParam:param];
// Here we call the method to test and we would do an assertion of its returned value...
[YourClassToTest foo:param];
OCMock3
// Parameter
NSURL *url = [NSURL URLWithString:#"http://testURL.com"];
// Set up the class to mock `alloc` and `init...`
id mockController = OCMClassMock([WebAuthViewController class]);
OCMStub([mockController alloc]).andReturn(mockController);
OCMStub([mockController initWithAuthenticationToken:OCMOCK_ANY authConfig:OCMOCK_ANY]).andReturn(mockController);
// Expect the method that needs to be called correctly
OCMExpect([mockController handleAuthResponseWithURL:url]);
// Call the method which does the work
[self.myClassInstance authStarted];
OCMVerifyAll(mockController);
Notes
Ensure that in both cases you stub two methods (alloc and the init... method). Also, make sure that both stubbing calls are made on the instance of the class mock (not the class itself).
Docs: Class methods section in the OCMock features
Alternatives
This (strange)solution may be useful in case you want to test legacy code that due to whatever reason you cannot refactor. However, if you can modify the code you should refactor it and get an ExtClass object as a parameter, not a string, delegating the creation of ExtClass out of that method. Your production and test code would be simpler and clearer, specially in a more complex real life case, not in this simple example.
I am new to Objective C and I'm getting confused by this concept.
The following method is supposed to create instances of the class that is passed as a parameter and edit the instance's variables.
- (void) createObject:(Class)objecttype atPoint: (CGPoint)position {
if ([objecttype isSubclassOfClass:[GameObject class]]){
id theobject = [[objecttype alloc] init];
theobject.x = position.x; //error
theobject.y = position.y; //error
}
}
I get an error message where indicated above : Property 'x' not found on object of type '__strong id'
It seems like it should be simple, but I don't understand whats wrong.
The dot notation will not call methods on objects of type id.
Change that allocation line to:
GameObject *theobject = (GameObject*)[[objecttype alloc] init];
Note that, because of the isSubclassOfClass: conditional, the above cast is precisely correct.
I would like to build the invocation using NSClassFromString and NSSelectorFromString for the class method and the selector.
I tried to build invocation in the following way:
NSMethodSignature *signature;
NSInvocation *inv;
Class targetClass = NSClassFromString(#"NSString");
SEL selector = NSSelectorFromString(#"stringWithString:");
id arg = #"argument";
Method method = class_getInstanceMethod(targetClass, selector);
// why is the method nil when I run the code?
struct objc_method_description* desc = method_getDescription(method);
if (desc == NULL || desc->name == NULL){
return nil;
}
signature = [NSMethodSignature signatureWithObjCTypes:desc->types];
inv = [NSInvocation invocationWithMethodSignature:signature];
[inv setSelector:selector];
[inv setArgument:&arg atIndex:2];
[inv invoke];
__autoreleasing id returnObj;
[inv getReturnValue:&returnObj]; // get created object
Since 'method' is always 'nil' this approach does not work. Why?
What is the proper way to execute class method via invocation for the above code?
Your code is too complicated. You can get an NSMethodSignature* object without messing around with the runtime.
signature = [NSString methodSignatureForSelector:#selector(stringWithString:)];
stringWithString: is a class method, your code is using class_getInstanceMethod().
Try changing class_getInstanceMethod() to class_getClassMethod().
I have a note class with the following:
#interface Note
-(char)alphabetName;
#end
And I am trying to stub this out in a test:
id mockNote = [OCMockObject mockForClass:[Note class]];
[[[mockNote stub] andReturnValue:OCMOCK_VALUE((char){'A'})] alphabetName];
And my test suite will not run due to getting an error on the stub call: "Taking the address of a temporary object of type 'char'"
I can't reproduce this error. What happens if you get rid of the temporary?
id mockNote = [OCMockObject mockForClass:[Note class]];
char a = 'A';
[[[mockNote stub] andReturnValue:OCMOCK_VALUE(&a)] alphabetName];