Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can the return value of an OCMock stub be changed?

It seems that the first time I add andReturnValue on an OCMock stub, that return value is set in stone. For example:

id physics = [OCMockObject niceMockForClass:[DynamicPhysicsComponent class]
Entity *testEntity = [Entity entityWithPhysicsComponent:physics];
CGPoint velocity1 = CGPointMake(100, 100);
CGPoint velocity2 = CGPointZero;
[[[physics stub] andReturnValue:OCMOCK_VALUE(velocity1)] getCurrentVelocity];
[testEntity update:0.1];
[[[physics stub] andReturnValue:OCMOCK_VALUE(velocity2)] getCurrentVelocity];
[testEntity update:0.1];

The stubbed method is called in [testEntity update]. But each time the stubbed method is returning the velocity1 value, so I guess the second attempt to set the methods return value isn't honoured.

Is there a way to do do this in OCMock?

like image 416
Cris Avatar asked Apr 14 '11 04:04

Cris


2 Answers

When you stub a method, you're saying it should always function in the specified way, no matter how many times it's called. The easiest way to fix this is to change stub to expect:

CGPoint velocity1 = CGPointMake(100, 100);
CGPoint velocity2 = CGPointZero;
[[[physics expect] andReturnValue:OCMOCK_VALUE(velocity1)] getCurrentVelocity];
[testEntity update:0.1];
[[[physics expect] andReturnValue:OCMOCK_VALUE(velocity2)] getCurrentVelocity];
[testEntity update:0.1];

Alternatively, if you need to stub (for example if the method might not be called at all), you can just re-create the mock:

CGPoint velocity1 = CGPointMake(100, 100);
CGPoint velocity2 = CGPointZero;
[[[physics stub] andReturnValue:OCMOCK_VALUE(velocity1)] getCurrentVelocity];
[testEntity update:0.1];
[physics verify];

physics = [OCMockObject mockForClass:[Physics class]];
[[[physics stub] andReturnValue:OCMOCK_VALUE(velocity2)] getCurrentVelocity];
[testEntity update:0.1];
[physics verify];
like image 109
Christopher Pickslay Avatar answered Nov 01 '22 22:11

Christopher Pickslay


Actually when you stub you're only setting the return value in stone if you use andReturn or andReturnValue. You can use the method andDo to change the returned value whenever you want. This is a improvement over expect where you need to know how many times a method will get called. Here the code snippet to accomplish this:

__weak TestClass *weakSelf = self;
[[[physics stub] andDo:^(NSInvocation *invocation) {
    NSValue *result = [NSValue valueWithCGPoint:weakSelf.currentVelocity];
    [invocation setReturnValue:&result];
}] getCurrentVelocity];
like image 30
Patrik Avatar answered Nov 01 '22 23:11

Patrik