Передача примитивов в заглушку OCMock - PullRequest
30 голосов
/ 13 июня 2011

Я изучаю, как использовать OCMock для тестирования проекта моего iPhone, и у меня есть такой сценарий: класс HeightMap с методом getHeightAtX:andY: и класс Render с использованием HeightMap. Я пытаюсь выполнить модульный тест рендера, используя несколько HeightMap макетов. Это работает:

id mock = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[mock stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:0 andY:0];

Конечно, работает только для x=0 и y=0. Я хочу проверить, используя "плоскую" карту высот. Это означает, что мне нужно сделать что-то вроде этого:

id chunk = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[chunk stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:[OCMArg any] andY:[OCMArg any]];

Но это вызывает два предупреждения компиляции:

предупреждение: передача аргумента 1 из 'getHeightAtX:andY:' делает целое число из указателя без приведения

и ошибка времени выполнения:

неожиданный вызванный метод: 'getHeightAtX:0 andY:0 stubbed: getHeightAtX:15545040 andY:15545024'

Чего мне не хватает? Я не нашел способа передать anyValue этому издевательству.

Ответы [ 6 ]

49 голосов
/ 08 ноября 2013

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

[[[mockObject expect] ignoringNonObjectArgs] someMethodWithPrimitiveArgument:5];

5 на самом деле ничего не делает, просто значение наполнителя

18 голосов
/ 13 июня 2011

OCMock в настоящее время не поддерживает слабое соответствие примитивных аргументов. На форумах OCMock обсуждается потенциальное изменение поддержки , хотя, похоже, оно застопорилось.

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

2 голосов
/ 23 мая 2013

Используйте OCMockito .

Поддерживает примитивное сопоставление аргументов.

Например, в вашем случае:

id chunk = mock([Chunk class]);
[[given([chunk getHeightAtX:0]) withMatcher:anything() forArgument:0] willReturnInt:0];
1 голос
/ 18 декабря 2014

В дополнение к ответу Эндрю Парка вы можете сделать его более общим и красивым:

#define OCMStubIgnoringNonObjectArgs(invocation) \
({ \
    _OCMSilenceWarnings( \
        [OCMMacroState beginStubMacro]; \
        [[[OCMMacroState globalState] recorder] ignoringNonObjectArgs]; \
        invocation; \
        [OCMMacroState endStubMacro]; \
    ); \
})

Вы можете использовать это так:

OCMStubIgnoringNonObjectArgs(someMethodParam:0 param2:0).andDo(someBlock)

Вы можете сделать то же самое для ожидания. Этот случай для заглушки в качестве начального запроса к теме. Он был протестирован с OCMock 3.1.1.

0 голосов
/ 04 мая 2018

Вы можете сделать так: id chunk = OCMClassMock([Chunk class]) OCMStub([chunk ignoringNonObjectArgs] getHeightAtX:0 andY:0]])

Подробнее на: http://ocmock.org/reference/#argument-constraints

0 голосов
/ 05 мая 2017

Несмотря на довольно хакерский подход, подход с использованием ожиданий для сохранения переданного блока для последующего вызова в тестовом коде сработал для меня:

- (void)testVerifyPrimitiveBlockArgument
{
    // mock object that would call the block in production
    id mockOtherObject = OCMClassMock([OtherObject class]);

    // pass the block calling object to the test object
    Object *objectUnderTest = [[Object new] initWithOtherObject:mockOtherObject];

    // store the block when the method is called to use later
    __block void (^completionBlock)(NSUInteger value) = nil;
    OCMExpect([mockOtherObject doSomethingWithCompletion:[OCMArg checkWithBlock:^BOOL(id value) { completionBlock = value; return YES; }]]);

    // call the method that's being tested
    [objectUnderTest doThingThatCallsBlockOnOtherObject];

    // once the expected method has been called from `doThingThatCallsBlockOnOtherObject`, continue
    OCMVerifyAllWithDelay(mockOtherObject, 0.5);
    // simulate callback from mockOtherObject with primitive value, can be done on the main or background queue
    completionBlock(45);
}
...