如何更改OCMock存根的返回值?

时间:2011-04-14 04:22:43

标签: unit-testing ocmock

似乎第一次在OCMock存根上添加 andReturnValue ,该返回值是一成不变的。例如:

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];

在[testEntity update]中调用stubbed方法。但每次stubbed方法返回velocity1值,所以我猜第二次设置方法返回值的尝试不受尊重。

有没有办法在OCMock中做到这一点?

4 个答案:

答案 0 :(得分:37)

当你stub一个方法时,你会说它应该始终以指定的方式运行,无论它被调用多少次。解决此问题的最简单方法是将stub更改为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];

或者,如果您需要stub(例如,如果可能根本不调用该方法),您可以重新创建模拟:

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];

答案 1 :(得分:26)

实际上,当您stub时,如果您使用andReturnandReturnValue,则只能设置返回值。您可以使用方法andDo随时更改返回的值。这是对expect的改进,您需要知道调用方法的次数。这里是完成此任务的代码片段:

__weak TestClass *weakSelf = self;
[[[physics stub] andDo:^(NSInvocation *invocation) {
    NSValue *result = [NSValue valueWithCGPoint:weakSelf.currentVelocity];
    [invocation setReturnValue:&result];
}] getCurrentVelocity];

答案 2 :(得分:2)

虽然我认为CipherCom有正确的答案,但我发现自己更喜欢创建一个帮助类来返回各种值。我过去曾遇到NSInvocation的问题。

@interface TestHelper : NSObject
@property (nonatomic, assign) CGPoint velocity;
- (CGPoint)getCurrentVelocity;
@end

@implementation TestHelper
- (CGPoint)getCurrentVelocity
{
    return self.velocity;
}
@end

然后在我的测试类中,我有TestHelper的私有成员变量,而setUp方法我会这样做:

self.testHelper = [TestHelper new];

[[[physics stub] andCall:@selector(getCurrentVelocity) onObject:self.testHelper]
                 getCurrentVelocity]; 

在我的每个测试中,我都可以将速度设置为我想要的测试速度。

self.testHelper.velocity = CGPointMake(100, 200);

答案 3 :(得分:1)

在多次调用时,似乎andReturnValue / andDo / isAvailable都不会被覆盖。我的解决方法是向测试类添加一个属性,并使用它来控制模拟对象应返回的内容。例如,如果模拟对象上有@interface MyTest: XCTestCase @property BOOL stubbedIsAvailable; @end @implementation MyTest - (void)setUp { [OCMStub([myMockedObject isAvailable]) andDo:^(NSInvocation invocation) { BOOL retVal = self.stubbedIsAvailable; [invocation setReturnValue:&retVal]; } } - (void)testBehaviourWhenIsAvailable { self.stubbedIsAvailable = YES; // test the unit } - (void)testBehaviourWhenIsNotAvailable { self.stubbedIsAvailable = NOT; // test the unit } 属性,我的代码将如下所示:

<div class="bx-controls-direction"><a class="bx-prevs" href="">Prev</a><a class="bx-nexts" href="">Next</a></div>