Как можно изменить возвращаемое значение заглушки OCMock? - PullRequest
25 голосов
/ 14 апреля 2011

Кажется, что в первый раз, когда я добавляю andReturnValue в заглушку OCMock, это возвращаемое значение устанавливается в камне. Например:

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]. Но каждый раз, когда метод-заглушка возвращает значение speed1, я полагаю, что вторая попытка установить возвращаемое значение метода не выполняется.

Есть ли способ сделать это в OCMock?

Ответы [ 4 ]

37 голосов
/ 14 апреля 2011

Когда вы 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];
26 голосов
/ 02 ноября 2012

На самом деле, когда вы stub вы устанавливаете возвращаемое значение в камне, только если вы используете andReturn или andReturnValue. Вы можете использовать метод andDo для изменения возвращаемого значения в любое время. Это улучшение по сравнению с expect, когда вам нужно знать, сколько раз будет вызван метод. Вот фрагмент кода для этого:

__weak TestClass *weakSelf = self;
[[[physics stub] andDo:^(NSInvocation *invocation) {
    NSValue *result = [NSValue valueWithCGPoint:weakSelf.currentVelocity];
    [invocation setReturnValue:&result];
}] getCurrentVelocity];
2 голосов
/ 16 марта 2015

Хотя я думаю, что 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);

1 голос
/ 20 января 2016

Похоже, что ни один из них 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
}
...