似乎我第一次在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]中调用。但是每次存根方法都返回velocity1值,所以我猜第二次尝试设置方法返回值是不被尊重的。
在OCMock中有办法做到这一点吗?
当你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];
实际上,当您使用andReturn
或andReturnValue
时,您只在石头中设置返回值。您可以随时使用andDo
方法来更改返回值。这是对expect
的改进,在CC_9中,您需要知道一个方法将被调用多少次。下面是完成这个任务的代码片段:
__weak TestClass *weakSelf = self;
[[[physics stub] andDo:^(NSInvocation *invocation) {
NSValue *result = [NSValue valueWithCGPoint:weakSelf.currentVelocity];
[invocation setReturnValue:&result];
}] getCurrentVelocity];
虽然我认为CipherCom有正确的答案,但我发现自己更喜欢创建一个用于返回各种值的helper类。我过去在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);
看起来andReturn
/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
}