Mock objects skipping chained method calls?

Discussion of the OCMock framework. If you have patches we would prefer you to send them to the mailing list, but attaching them to a topic is possible, too.

Mock objects skipping chained method calls?

Postby eeyore » 25 Oct 2010, 17:06

I'm new to Obj-C (6 months) and OCMock (2 weeks), so this may be a misunderstanding of how these things are supposed to work, but it appears that my mock objects are skipping chained function calls if the mock's return value from an inner call matches the expected return value of an outer call. Here's the situation:

@implementation MWRacer

+ (BOOL)existsRacerWithFirst: (NSString*)first last: (NSString*)last
return [MWDatabase isValidId: [MWDatabase racerIdWithFirst: first last: last]];

@interface MWDatabase

+ (NSInteger)racerIdWithFirst: (NSString*)first last: (NSString*)last;
- (NSInteger)MWImp_racerIdWithFirst: (NSString*)first last: (NSString*)last;
+ (BOOL)validId: (NSInteger)id;
- (BOOL)MWImp_validId: (NSInteger)id;

@implementation MWDatabase

+ (NSInteger)racerIdWithFirst: (NSString*)first last: (NSString*)last
return [[MWDatabase sharedInstance] MWImp_racerIdWithFirst: first last: last];

+ (BOOL)isValidId: (NSInteger)id
return [[MWDatabase sharedInstance] MWImp_isValidId: id];

While testing, I am filtering the class methods through instance methods of a shared object (instance methods prefixed with MWImp_) so that I can mock them. This has appeared to work since all my other tests are passing/failing as expected. However, in this case, it doesn't matter which of the #if branches are taken, the test is passed. I would have expected the second branch to result in failure since I am returning the wrong type (a BOOL, not an NSInteger) and don't expect isValidId to be called.

BOOL theYes = YES;
NSInteger theOne = 1;

theMockDB = [OCMockObject mockForClass: [MWDatabase class]];
#if 0
[[[theMockDB expect] andReturnValue: OCMOCK_VALUE(theOne)]MWImp_racerIdWithFirst: @"First" last: @"Last"];
[[[theMockDB expect] andReturnValue: OCMOCK_VALUE(theYes)]MWImp_isValidId: 1];
[[[theMockDB expect] andReturnValue: OCMOCK_VALUE(theYes)] MWImp_racerIdWithFirst: @"First" last: @"Last"];
[theMockDB expect close];

[MWDatabase setSharedInstance: theMockDB];
@try {
MWTAssertTrue([MWRacer existsRacerWithFirst: @"First" last: @"Last"]);
} @catch(...) {}
[MWDatabase setSharedInstance: nil];
[theMockDB verify];

If this isn't expected behavior and you aren't seeing it, let me know and I will try to put together a small project that exhibits it.


Return to OCMock