14

One of the parameter of my method is **error and my project is in ARC mode. When writing stub for this method to call a mock method i set parameter to below possible values. Either it causes compile error or failing to match the argument to call the mock method.

  1. OCMOCK_ANY
  2. [OCMArg anyPointer]
  3. Created a NSError object error and said [OCMArg setTo:error].

Nothing works.

How to mock such method? Please advice.

Edit

-(id)init{

    self = [super init];

    if (self) {
        id wcm = [OCMockObject partialMockForObject:self];
        [[[wcm stub] andCall:@selector(mockGetWakeupCallsForRoomNumber:error:)    onObject:self] getWakeupCallsForRoomNumber:OCMOCK_ANY error:((NSError __autoreleasing **)    [OCMArg anyPointer])];
        //[[[wcm stub] andCall:@selector(testMockMethod) onObject:self] testMethod];

    }
    return self;

}

-(void)testMethod
{
    NSLog(@"Original");
}

-(void)testMockMethod
{
    NSLog(@"Mock");
}
-(NSArray*)mockGetWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error
{
    @throw @"Mock method called";
}

-(NSArray*)getWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error
{
}

Mock on testMockMethod works.

Saran
  • 6,274
  • 3
  • 39
  • 48

2 Answers2

20

You can use setTo: or anyPointer if you cast it:

[[[mockFoo expect] andReturn:nil] someMethodWithError:((NSError __autoreleasing **)[OCMArg anyPointer])];

or:

NSError *error;
[[[mockFoo expect] andReturn:nil] someMethodWithError:((NSError __autoreleasing **)[OCMArg setTo:error])];

Here's a test case that passes with the method you've posted:

@interface Foo : NSObject{}

-(NSArray*)mockGetWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error;
-(NSArray*)getWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error;

@end

@implementation Foo

-(NSArray*)mockGetWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error
{
    return @[@"bar"];
}

-(NSArray*)getWakeupCallsForRoomNumber:(NSString*)roomNumber error:(NSError**)error
{
    return nil;
}

@end

@interface SomeTest : SenTestCase {}
@end

@implementation SomeTest

-(void)testMethod
{
    Foo *foo = [Foo new];
    id wcm = [OCMockObject partialMockForObject:foo];
    [[[wcm stub] andCall:@selector(mockGetWakeupCallsForRoomNumber:error:) onObject:foo] getWakeupCallsForRoomNumber:OCMOCK_ANY error:((id __autoreleasing *)[OCMArg anyPointer])];
    NSError *error;
    NSArray *calls = [wcm getWakeupCallsForRoomNumber:@"foo" error:&error];
    STAssertEquals(calls[0], @"bar", @"should match");
}

@end
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
  • [[[wcm stub] andCall:@selector(mockGetWakeupCallsForRoomNumber:error:) onObject:self] getWakeupCallsForRoomNumber:OCMOCK_ANY error:((NSError __autoreleasing **)[OCMArg anyPointer])]; calls are not invoking the mock method. Please help. – Saran Aug 17 '13 at 17:07
  • Please add the test case and the code you're testing to your question. – Christopher Pickslay Aug 17 '13 at 19:08
  • Added the code. This is in library responsible to connect backend server. My intention is to have the ability to provide mock until required service is implemented at the backend. – Saran Aug 17 '13 at 19:37
  • Is this something we could improve in OCMock? Is there any way to declare the anyPointer/setTo: methods so that the cast isn't needed? – Erik Doernenburg Aug 17 '13 at 19:54
  • @Galaxy see my updated answer, with a passing test case. In the code you added, it looks like you're trying to create a partial mock of a test class, which I would not expect to behave well. But with a real-world case of mocking another class, it works fine. – Christopher Pickslay Aug 19 '13 at 17:33
  • @ErikDoernenburg the test case works with the more generic cast `(id __autoreleasing *)`. Perhaps `anyPointer` could be updated to return `(id __autoreleasing *)`, though I'm not sure if there might be other side effects. – Christopher Pickslay Aug 19 '13 at 17:35
  • @ChristopherPickslay, thanks. With a minor improvement it is working good. I added another parameter in the mean time:) [[[wcm stub] andCall:@selector(getWakeupCallsForRoomNumber:error:serverMessage:) onObject:self] getWakeupCallsForRoomNumber:OCMOCK_ANY error:((NSError *__autoreleasing *)[OCMArg anyPointer]) serverMessage:((NSString *__autoreleasing *)[OCMArg anyPointer])]; – Saran Aug 23 '13 at 09:12
  • @ChristopherPickslay Don't want to make this too off-topic. That said, I think an additional method on OCMArg could help, e.g. anyObjectRef. We could leave anyPointer as generic as it is and for cases like this provide a differently typed version. – Erik Doernenburg Aug 27 '13 at 09:24
  • @ChristopherPickslay, take a look at my answer. It doesn't have to be id. Can be more specific like (NSString *__autoreleasing *)[OCMArg anyPointer] – Saran Aug 27 '13 at 13:13
  • This is ancient now, but OCMock now has `[OCMArg anyObjectRef]` that should allow you to avoid the cast and reads a little better. – dmaclach May 10 '20 at 18:08
2

Finally this is what i implemented.

[
 [[wcm stub] 
           andCall:@selector(getWakeupCallsForRoomNumber:error:serverMessage:) 
   onObject:self]
   getWakeupCallsForRoomNumber:OCMOCK_ANY
                         error:((NSError *__autoreleasing *)[OCMArg anyPointer]) 
                 serverMessage:((NSString *__autoreleasing *)[OCMArg anyPointer])];
Maxim Shoustin
  • 77,483
  • 27
  • 203
  • 225
Saran
  • 6,274
  • 3
  • 39
  • 48