2013-05-24 2 views
3

в моем арматуре нАлАдкА я следующееOcMock - Заглушка/ожидание/stopmocking

-(void)setUp{ 
    _vc = [OCMockObject partialMockForObject:[[InboxViewController alloc] init]]; 
    //stub out the view stuff 
    [[_vc stub] removeTask:OCMOCK_ANY]; 
    [[_vc stub] insertTask:OCMOCK_ANY]; 
} 

Есть 15 тестов в арматуре, однако, мне нужно на самом деле проверить, что эти 2 методы вызываются, так что я написал 2 испытания

-(void)someTest{ 
    [[_vc expect] removeTask:OCMOCK_ANY]; 
    [_vc removeAllTasksFromList:taskList notInList:newTaskList]; 
    [_vc verify]; 
} 

но что тест не

я также попытался

-(void)someTest{ 
    [[_vc stopMocking]; 
    [[_vc expect] removeTask:OCMOCK_ANY]; 
    [[_vc stub] removeTask:OCMOCK_ANY]; 
    [_vc removeAllTasksFromList:taskList notInList:newTaskList]; 
    [_vc verify]; 
} 

Но тест все еще не удается. Я что-то упустил, или так работает OCMock?

Единственный способ, которым я могу заставить его работать, как это

-(void)someTest{ 
    //re create and init the mock object 
    _vc = [OCMockObject partialMockForObject:[[InboxViewController alloc] init]]; 
    [[_vc expect] removeTask:OCMOCK_ANY]; 
    [[_vc stub] removeTask:OCMOCK_ANY]; 
    [_vc removeAllTasksFromList:taskList notInList:newTaskList]; 
    [_vc verify]; 
} 

ответ

7

Возможно, документация должна быть более четкой. То, что stopMocking делает для частичного макета, является восстановление реального объекта, в вашем случае InboxViewController, в его исходное состояние. Вызов stopMocking не сбрасывает макет объекта, что означает, что он не очищает заглушки и ожидания. Вы всегда можете позвонить stopMocking, а затем создать новый макет для одного и того же реального объекта.

Как было указано в другом ответе, как правило, лучше избегать обхода и ожидая того же метода, но если вам нужно это сделать, обязательно настройте ожидание перед заглушкой; в противном случае заглушка будет обрабатывать вызовы, и ожидание никогда их не увидит.

Я знаю, что традиционно многие люди рекомендуют использовать метод установки для настройки объекта теста. Мой личный опыт на протяжении многих лет заключается в том, что это вообще не стоит. Сохранение нескольких строк в каждом тесте может выглядеть привлекательно, но в конце концов оно создает связь между отдельными тестами, делая набор более хрупким.

+4

Хороший вопрос о том, как извлечение испытуемого создает соединение! – Christoph

2

Кажется, что вам нужно, чтобы создать новый макет, чтобы ожидать, метод, который вы уже погасил. Я бы порекомендовал вам пересмотреть использовать частичную издеваться во всех тестовых случаях, и если вы хотите так, извлечь этот:

[[_vc stub] removeTask:OCMOCK_ANY]; 
[[_vc stub] insertTask:OCMOCK_ANY]; 

в вспомогательный метод и вызывать этот метод из тестов вы действительно нуждаются в этом, удалив его из вашего метода setUp.

И, маленький наконечник :), вы должны позвонить в [super setUp] в начале вашей setUp реализации.

+0

Это всего лишь образец кода. Я на самом деле звоню в супер-настройку. Кажется, что укутывание до ожидания не работает. Но я не понимаю, почему это не перестает насмехаться, а затем ждать, пока не закончится работа –

0

Порядок, в котором заданы заглушки и ожидающие вызовы, важен для частичного макета. Остановка метода до того, как он будет ожидаться, будет означать, что любые сообщения, отправленные на закодированный метод, никогда не будут соответствовать ожиданию.

С другой стороны, stopMocking просто означает, что частичный макет перестает связываться с реальным объектом. Макет все еще держит свои рекордеры (окурки и ожидания) и работает как обычно. Вы можете проверить это, отправив removeAllTasksFromList:notInList на ваш реальный объект, который в этом случае не назначен какой-либо переменной. В этом случае вы увидите, что сообщение действительно достигает реализации вашего объекта. Тем не менее, макет все равно не сможет выполнить проверку. В общем, вы должны вызывать методы на вашем реальном объекте. Частичный макет все равно будет перехватывать сообщения.

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

- (void) setUpPartialMockWithExpect:(BOOL)needExpect { 
    _vc = [OCMockObject partialMockForObject:[[InboxViewController alloc] init]]; 

    if(needExpect) 
     [[_vc expect] removeTask:OCMOCK_ANY]; 

    //stub out the view stuff 
    [[_vc stub] removeTask:OCMOCK_ANY]; 
    [[_vc stub] insertTask:OCMOCK_ANY]; 
} 

И позвони, что в каждом из вашего -(void)test...

1

Пару вещей отметить:

  1. Вы должны сохранить ссылку на реальный объект вас» переодевшись. Вызывать ложную настройку/проверку на макет ссылки и методы, которые вы тестируете на самом объекте.
  2. Вы не должны заглушать и ожидать того же вызова метода. Штук будет соответствовать, и ожидание не пройдет.

Я предполагаю, что вы обманываете setUp, потому что у вас есть методы, которые могут или не могут быть вызваны в тестах.Если это так, вы можете структурировать свои тесты следующим образом:

static InboxViewController *_vc; 
static id mockInbox; 

-(void)setUp{ 
    _vc = [[InboxViewController alloc] init]; 
    mockInbox = [OCMockObject partialMockForObject:_vc]; 
    //stub out the view stuff 
    [[mockInbox stub] removeTask:OCMOCK_ANY]; 
    [[mockInbox stub] insertTask:OCMOCK_ANY]; 
} 

-(void)someTest{ 
    [[mockInbox expect] somethingIExpectForThisTest:OCMOCK_ANY]; 
    [_vc removeAllTasksFromList:taskList notInList:newTaskList]; 
    [mockInbox verify]; 
} 

-(void)someOtherTest{ 
    [[mockInbox expect] someOtherThingIExpectForThisTest:OCMOCK_ANY]; 
    [_vc doSomethingElse]; 
    [mockInbox verify]; 
} 
+0

. Интересно, что это вызывает еще одну проблему с ocmock. Вы не можете заглушить, прежде чем ожидать. Он не прошел тест. Я на самом деле попросил разработчиков ocmock об этом, но еще не получил ответа –

+1

. Один из ответов содержит более подробную информацию, но, в основном, если вы создадите заглушку, сначала обработайте все вызовы, а ожидания не увидит ее, и тогда макет будет жаловаться на проверку. Обычно вы либо хотите ожидать метода, либо его заглушить, но не оба. Я предполагаю, что в OCMock все еще отсутствует модификатор «atLeastOnce», поэтому ожидание методов, которые можно вызвать несколько раз, становится проще. –

2

Вы можете сделать следующее, чтобы удалить заглушки из OCMockObject, что позволит вам сохранить stub код в -(void)setUp, но все же позволяют добавить expect в последующем испытании.

Добавьте к вашему тесту следующую категорию, чтобы вернуть OCMockObject ivar.

@interface OCMockObject (Custom) 
- (void)removeStubWithName:(NSString*)stubName; 
@end 

@implementation OCMockObject (Custom) 
- (void)removeStubWithName:(NSString*)stubName { 
    NSMutableArray* recordersToRemove = [NSMutableArray array]; 
    for (id rec in recorders) { 
     NSRange range = [[rec description] rangeOfString:stubName]; 
     if (NSNotFound == range.location) continue; 
     [recordersToRemove addObject:rec]; 
    } 
    [recorders removeObjectsInArray:recordersToRemove]; 
} 
@end 

Пример использования: Убедитесь, что вы удалите заглушку для метода перед добавлением ожидать.

-(void)someTest{ 
    [_vc removeStubWithName:@"removeTask"]; 
    [[_vc expect] removeTask:OCMOCK_ANY]; 
    [_vc removeAllTasksFromList:taskList notInList:newTaskList]; 
    [_vc verify]; 
} 

Это позволит вашему тесту работать, как вы ожидаете.

Это полезный взлом, по крайней мере, до тех пор, пока разработчики OCMock не позволят эту функциональность.

+0

Это правильный ответ и прекрасный хак. Благодарю. – ajmccall