ocmock
Mock objects for Objective-C
Front Page · OCMock
I have created a mock UINavigationController using OCMock. However, I cannot assign it to the navigationController property of a UIViewController since that property is readonly.
id mockNavController = [OCMockObject mockForClass:[UINavigationController class]];
...
myViewController.navigationController = mockNavController; // readonly!
The author of this blog post claims to have found a solution but neglected to share it.
Source: (StackOverflow)
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?
Source: (StackOverflow)
I'm wondering how to go about testing this. I have a method that takes a parameter, and based on some properties of that parameter it creates another object and operates on it. The code looks something like this:
- (void) navigate:(NavContext *)context {
Destination * dest = [[Destination alloc] initWithContext:context];
if (context.isValid) {
[dest doSomething];
} else {
// something else
}
[dest release];
}
What i want to verify is that if context.isValid is true, that doSomething is called on dest, but i don't know how to test that (or if that's even possible) using OCMock or any other traditional testing methods since that object is created entirely within the scope of the method. Am i going about this the wrong way?
Source: (StackOverflow)
I'm trying to mock a UITabBarController in my app's tests. I have a category method on that class defined elsewhere in another file that gets imported along with ocmock in my test class. what i'm trying to so is this:
- (void) setUp
{
id mockTabController = [OCMockObject mockForClass:[UITabBarController class]];
[[[mockTabController stub] andReturn:nil] displayedViewController];
// displayedViewController is the category method
}
but when i do and the test gets to that stub call, i get an error saying:
[NSProxy doesNotRecognizeSelector:displayedViewController] called!
Is there something specific i need to do to allow ocmock to recognize category methods on built in framework classes?
Source: (StackOverflow)
Consider this code, which works (the loginWithEmail method gets expected as, well, expected):
_authenticationService = [[OCMockObject mockForClass:[AuthenticationService class]] retain];
[[_authenticationService expect] loginWithEmail:[OCMArg any] andPassword:[OCMArg any]];
Versus this code:
_authenticationService = [[OCMockObject mockForProtocol:@protocol(AuthenticationServiceProtocol)] retain];
[[_authenticationService expect] loginWithEmail:[OCMArg any] andPassword:[OCMArg any]];
The second code example fails on line 2 with the following error:
*** -[NSProxy doesNotRecognizeSelector:loginWithEmail:andPassword:] called! Unknown.m:0: error: -[MigratorTest methodRedacted] : ***
-[NSProxy doesNotRecognizeSelector:loginWithEmail:andPassword:] called!
AuthenticationServiceProtocol declares the method:
@protocol AuthenticationServiceProtocol <NSObject>
@property (nonatomic, retain) id<AuthenticationDelegate> authenticationDelegate;
- (void)loginWithEmail:(NSString *)email andPassword:(NSString *)password;
- (void)logout;
- (void)refreshToken;
@end
And it is implemented in the class:
@interface AuthenticationService : NSObject <AuthenticationServiceProtocol>
This is using OCMock for iOS.
Why does expect
fail when the mock is a mockForProtocol
?
Source: (StackOverflow)
I am going through an application and adding Unit Tests. The application is written using storyboards and supports iOS 6.1 and above.
I have been able to test all the usual return methods with no problem. However I am currently stumped with a certain test I want to perform:
Essentially I have a method, lets call it doLogin:
- (IBAction)doLogin:(UIButton *)sender {
// Some logic here
if ( //certain criteria to meet) {
variable = x; // important variable set here
[self performSegueWithIdentifier:@"memorableWord" sender:sender];
} else {
// handler error here
}
So I want to test that either the segue is called and that the variable is set, or that the MemorableWord view controller is loaded and the variables in there are correct. The variable set here in the doLogin method is passed through to the memorableWord segues' destination view controller in the prepareForSegue method.
I have OCMock set up and working, and I am also using XCTest as my unit testing framework. Has anyone been able to product a unit test to cover such a situation??
It seems that Google and SO are pretty bare in regards to information around this area.. lots of examples on simple basic tests that are pretty irrelevant to the more complex reality of iOS testing.
Source: (StackOverflow)
I am trying to use OCMock 1.77 for unit and application testing with iOS4 and Xcode 4/SDK4.3. I have followed the instructions to do using OCMock as a static library found here: http://www.mulle-kybernetik.com/software/OCMock/. The unit and application tests run fine without OCMock.
When I add OCMock and try to run OCMock's test suite for the simulator (unit tests), my test rig crashes with code 134. The test rig runs fine for a device (application tests). If I look in the console, I see the message below -- which suggests that I haven't added the -force_load linker flag per the instructions at the above URL. But I have... Any thoughts?
I looked at this: Test rig exited abnormally with code 134 with OCMock verify on iOS 4 which suggests this behavior is a bug -- but I'm not sure it is the same situation since I am running the OCMock test suite. If it is a bug, is there a work-around to use mocks in unit testing?
TIA.
=====
Console output:
3/30/11 1:02:32 AM otest[38552] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '** Expected method not present; the method getArgumentAtIndexAsObject: is not implemented by NSInvocation. If you see this exception it is likely that you are using the static library version of OCMock and your project is not configured correctly to load categories from static libraries. Did you forget to add the -force_load linker flag?'
*** Call stack at first throw:
(
0 CoreFoundation 0x004a05a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x002cf313 objc_exception_throw + 44
2 CoreFoundation 0x00458ef8 +[NSException raise:format:arguments:] + 136
3 CoreFoundation 0x00458e6a +[NSException raise:format:] + 58
4 LogicTests 0x00f89de4 +[OCMockObject initialize] + 115
5 libobjc.A.dylib 0x002cfd9b _class_initialize + 380
6 libobjc.A.dylib 0x002d773f prepareForMethodLookup + 73
7 libobjc.A.dylib 0x002ce069 lookUpMethod + 86
8 libobjc.A.dylib 0x002ce1d6 _class_lookupMethodAndLoadCache + 40
9 libobjc.A.dylib 0x002e10e3 objc_msgSend + 87
10 SenTestingKit 0x20108824 +[NSObject(SenTestRuntimeUtilities) senAllSubclasses] + 107
11 SenTestingKit 0x201074a7 +[SenTestSuite updateCache] + 39
12 SenTestingKit 0x20107443 +[SenTestSuite suiteForBundleCache] + 92
13 SenTestingKit 0x201073a4 +[SenTestSuite testSuiteForBundlePath:] + 108
14 SenTestingKit 0x2010606b +[SenTestProbe specifiedTestSuite] + 332
15 SenTestingKit 0x20106792 +[SenTestProbe runTests:] + 156
16 otest 0x000023c7 0x0 + 9159
17 otest 0x000025f2 0x0 + 9714
18 otest 0x0000209a 0x0 + 8346
19 otest 0x00002049 0x0 + 8265
)
Source: (StackOverflow)
i am making a GET
request to retrieve JSON
data with AFNetworking
as this code below :
NSURL *url = [NSURL URLWithString:K_THINKERBELL_SERVER_URL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
Account *ac = [[Account alloc]init];
NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[NSString stringWithFormat:@"/user/%@/event/%@",ac.uid,eventID] parameters:nil];
AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError *error = nil;
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
}
[self.delegate NextMeetingFound:[[Meeting alloc]init] meetingData:JSON];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error){
}];
[httpClient enqueueHTTPRequestOperation:operation];
the thing is i want to create a unit test based on this data, but i dont want that the test will actually make the request. i want a predefined structure will return as the response. i am kind'a new to unit testing, and poked a little of OCMock
but cant figure out how to manage this.
Source: (StackOverflow)
I'm hitting a road block and I'm wondering if the brilliant collective minds here can help. In ObjC CocoaTouch I'm trying to mock an object that takes struct parameters and returns a struct. OCMock is coughing up a hair-ball so I tried wrapping with a Hamcrest matcher. No die. The function/method I'm testing looks something like this:
- (CLLocationCoordinate2D)pixelToLatLong:(CGPoint)aPoint;
I use code like this:
#define OCMOCK_STRUCT(atype, variable) [NSValue value:&variable withObjCType:@encode(atype)]
-(void) testMyWidget
{
CLLocationCoordinate2D ulLL = (CLLocationCoordinate2D){123,456};
CLLocationCoordinate2D lrLL = (CLLocationCoordinate2D){654,321};
[[[(id)myObj expect] andReturn:OCMOCK_STRUCT(CLLocationCoordinate2D, ulLL)] pixelToLatLong:(CGPoint){0,0}];
[[[(id)myObj expect] andReturn:OCMOCK_STRUCT(CLLocationCoordinate2D, lrLL)] pixelToLatLong:(CGPoint){320,460}];//lower right point
}
That kinda works. So in my object that I'm testing I make the necessary required edits to get a green bar... err.. green button in the build info window. When I'm certain that my test should pass I get assertion failed errors. The errors inform me that the method was invoked unexpectedly and lists the values for these structs as question marks. I tried wrapping the structs with Hamcrest matchers but I'm getting nowhere. I'm getting ready to break out my debugger which will no doubt show me what's wrong. Has anybody here had similar trouble with OCMock/Hamcrest and structs? If so, what's the best way to handle these types?
Source: (StackOverflow)
i'm a new user of OCMock, so maybe i'm just missing something simple here. this code does not compile:
id mockSession = [OCMockObject mockForClass:[AVCaptureSession class]];
[[mockSession expect] addOutput:[OCMArg anyPointer]];
the error is
Multiple methods named 'addOutput:' found with mismatched result, parameter type or attributes
the signature of the method addOutput on AVCaptureSession is as follows
- (void)addOutput:(AVCaptureOutput *)output
as far as i can tell, the problem is that the method addOutput exists on both the AVCaptureSession and AVAssetReader classes. the method signature for addOutput on AVAssetReader is as follows.
- (void)addOutput:(AVAssetReaderOutput *)output
apparently the compiler thinks my mockSession is an AVAssetReader, but i don't know why it chooses that class instead of AVCaptureSession. if i expect a different method on AVCaptureSession that does not exist on AVAssetReader, then it compiles. i have tried the following without success. it compiles, but crashes.
id mockSession = [OCMockObject mockForClass:[AVCaptureSession class]];
[(AVCaptureSession*)[mockSession expect] addOutput:[OCMArg anyPointer]];
this code also does not compile, with the same error as the previous one
id mockSession = [OCMockObject mockForClass:[AVCaptureSession class]];
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[[mockSession expect] addOutput:output];
any guidance here?
Source: (StackOverflow)
Here's the method under test:
- (void)loginWithUser:(NSString *)userName andPass:(NSString *)pass {
NSDictionary *userPassD = @{@"user":userName,
@"pass":pass};
[_loginCntrl loginWithUserPass:userPassD withSuccess:^(NSString *authToken){
// save authToken to credential store
} failure:^(NSString *errorMessage) {
// alert user pass was wrong
}];
}
what I want to test is that in that success block the other dependency/OCMockObject _credStore is called with the appropriate methods. So currently the loginCtrl and credStore dependencies are OCMockObjects and I can stub/expect on those.
Would I stub loginController to somehow execute that block when called? I've looked at some of the questions on stubbing blocks with OCMock and I can't wrap my head around what they're doing and if it would be suitable for this situation.
In reality all I want to do is OCMock to fire the block ([success invoke]??) so that the code _credStore saveUserPass is done and can be verified on _credStore.
where I stopped:
- (void)test_loginWithuserPass_succeeds_should_call_credStore_setAuthToken {
NSDictionary *userPassD = @{@"user":@"mark",
@"pass":@"test"};
id successBlock = ^ {
// ??? isn't this done in the SUT?
};
[[[_loginController stub] andDo:successBlock] loginWithUserPass:userPassD withSuccess:OCMOCK_ANY failure:OCMOCK_ANY];
[[_credentialStore expect] setAuthToken:@"passed back value from block"];
[_docServiceSUT loginWithUser:@"mark" andPass:@"test"];
[_credentialStore verify];
}
ETA: here's what I have based on Ben's example below, but not working, getting a EXC_BAD_ACCESS exception:
// OCUnit test method
- (void)test_loginWithUserPass_success_block_should_call_credentials_setAuthToken {
void (^proxyBlock)(NSInvocation*) = ^(NSInvocation *invocation) {
void(^successBlock)(NSString *authToken);
[invocation getArgument:&successBlock atIndex:3]; // should be 3 because my block is the second param
successBlock(@"myAuthToken");
};
[[[_loginController expect] andDo:proxyBlock] loginWithUserPass:OCMOCK_ANY withSuccess:OCMOCK_ANY failure:OCMOCK_ANY];
[[_credentialStore expect] setAuthToken:@"myAuthToken"];
[_docServiceSUT loginWithUser:@"mark" andPass:@"myPass"];
[_loginController verify];
[_credentialStore verify];
}
//method under test
- (void)loginWithUser:(NSString *)userName andPass:(NSString *)pass {
NSDictionary *userPassD = @{@"user":userName,
@"pass":pass};
void(^onSuccess)(NSString *) = ^(NSString *authToken){
[SVProgressHUD dismiss];
[_credentials setAuthToken:authToken];
// Ask user to enter the 6 digit authenticator key
[self askUserForAuthenticatorKey];
};
void(^onFailure)(NSString *) = ^(NSString *errorMessage) {
[SVProgressHUD dismiss];
[_alertSender sendAlertWithMessage:errorMessage andTitle:@"Login failed"];
};
[SVProgressHUD show];
[_loginCntrl loginWithUserPass:userPassD withSuccess:onSuccess
failure:onFailure];
}
Source: (StackOverflow)
I am trying to write an block of code using OCMock's stub andDo method.
In this case UIImageView extension class is being tested. I want to check that the extension calls [self setImage:] with parameter that is non-nil (later other image comparison will be used).
When using OCMock's andDo method, the test crashes with EXC_BAD_ACCESS after the block completes.
id mockView = [OCMockObject mockForClass:[UIImageView class]];
[[[mockView stub] andDo:^(NSInvocation *invocation)
{
UIImage *img;
[invocation getArgument:&img atIndex:2]; <---- line causing the exception
somebodySetImage |= (img != nil);
}] setImage:OCMOCK_ANY];
[mockView do_something_that_calls_setImage];
The only solution that I've found for now is using andCall instead of andDo, but this complicates the test.
Can I avoid the crash with andDo?
UPDATE
Well, I will try to give a better example here:
Here is the new piece of the test code:
- (void)testDownloadingThumbnail
{
PInfo *_sut = [[PInfo alloc] init];
__block id target = nil;
id mock = [OCMockObject mockForClass:[NSOperationQueue class]];
[[[mock expect] andDo:^(NSInvocation *inv)
{
NSInvocationOperation *op;
[inv getArgument:&op atIndex:2];
target = [[op invocation] target]; /* replacing this line with STAssert does not help either */
}] addOperation:OCMOCK_ANY];
[_sut setDownloadQueue:mock];
[_sut startDownloadingImagesAsync:YES];
[mock verify];
STAssertEqualObjects(target, _sut, @"invalid op target");
}
Here is the tested code (single method from PInfo):
- (void)startDownloadingImagesAsync:(bool)isThumbnailImg
{
NSInvocationOperation *inv;
inv = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(loadThumbnailWorker:)
object:nil];
[[self downloadQueue] addOperation:inv];
}
The code still crashes upon exit from startDownloadingImagesAsync with EXC_BAD_ACCESS.
If I add a breakpoint inside the andDo block, I see that the control reaches this point and retrieves correct objects via getArgument.
Yet, if I use getArgument inside the block, it crashes whatever I try to do.
P.S. Thanks for help.
Source: (StackOverflow)
Under ARC
, I have an object, Child
that has a weak
property, parent
. I'm trying to write some tests for Child
, and I'm mocking its parent
property using OCMock
.
Under ARC, setting an NSProxy
subclass using a synthesized weak property setter doesn't set the property ... the line after the weak property is set, checking it reveals that it's already nil
. Here's the concrete example:
@interface Child : NSObject
@property (nonatomic, weak) id <ParentInterface>parent;
@end
@implementation Child
@synthesize parent = parent_;
@end
// ... later, inside a test class ...
- (void)testParentExists
{
// `mockForProtocol` returns an `NSProxy` subclass
//
OCMockObject *aParent = [OCMockObject mockForProtocol:@protocol(ParentInterface)];
assertThat(aParent, notNilValue());
// `Child` is the class under test
//
Child *child = [[Child alloc] init];
assertThat(child, notNilValue());
assertThat(child.parent, nilValue());
child.parent = (id<ParentInterface>)aParent;
assertThat([child parent], notNilValue()); // <-- This assertion fails
[aParent self]; // <-- Added this reference just to ensure `aParent` was valid until the end of the test.
}
I know that I can get around this using an assign
property instead of a weak
property for the Child
to reference the Parent
, but then I'd have to nil
out the parent
when I was done with it (like some sort of caveman), which is exactly the sort of thing that ARC was supposed to obviate.
Any suggestions on how to make this test pass without changing my app code?
Edit: It seems to have to do with OCMockObject
being an NSProxy
, if I make aParent
be an instance of NSObject
, the child.parent
weak reference "holds" a non-nil value. Still looking for a way to make this test pass without changing app code.
Edit 2: After accepting Blake's answer, I did an implementation in my project of a preprocessor macro that conditionally changed my properties from weak -> assign. Your mileage may vary:
#if __has_feature(objc_arc)
#define BBE_WEAK_PROPERTY(type, name) @property (weak, nonatomic) type name
#else
#define BBE_WEAK_PROPERTY(type, name) @property (assign, nonatomic) type name
#endif
Source: (StackOverflow)
We're trying to create a unit test (with OCMock although, open to other frameworks) that mocks a class that on class load has a side effect.
We have a tracking class that wraps calls to other tracking libraries like Flurry.
Many of these other tracking libraries (specifically, Flurry) execute code on class initialization.
The unit test fails as the code can't execute in a unit test environment. Ideally, we would like to replace the Flurry class with a mock/stub.
- (void) testConstruction {
[Flurry class];
}
When this code is called it attempts to use SCNetworkReachability
and receives exceptions
...
How can we stub/mock out calls to Flurry that has a static implementation like the following?
[Flurry setAppVersion:@"1.0"];
[Flurry setCrashReportingEnabled:NO];
Source: (StackOverflow)
I'm trying to mock a method that has the equivalent of the following signature:
- (NSDictionary *) uploadValues:(BOOL)doSomething error:(NSError **)error
I want it to return a small dictionary so that my test can make sure the code uses the dictionary properly. however, no matter what i do OCMock always returns nil from the method, regardless of how i stub it out. The error begins as nil in the code i'm testing, and these are the different ways i've tried stubbing it:
NSError * error = nil;
[[[mock stub] andReturn:someDict] uploadValues:YES error:&error];
[[[mock stub] andReturn:someDict] uploadValues:YES error:nil];
[[[mock stub] andReturn:someDict] uploadValues:YES error:[OCMArg any]];
and none of them work. Does OCMock support handles as stubbed message arguments and if so, what's the correct way to do it?
Source: (StackOverflow)