Как использовать макет и проверить методы OCMock в target-C? - PullRequest
0 голосов
/ 04 марта 2010

Моя проблема в том, что я получаю ошибку:

OCMckObject [NSNumberFormatter]: ожидаемого метода не было вызываемые: setAllowsFloats: ДА

Я написал следующий код:

(void) testReturnStringFromNumber
{
    id mockFormatter = [OCMockObject mockForClass:[NSNumberFormatter class]];
    StringNumber *testObject = [[StringNumber alloc] init];   

    [[mockFormatter expect] setAllowsFloats:YES];
    [testObject returnStringFromNumber:80.23456];
    [mockFormatter verify];
}


@implementation StringNumber

- (NSString *) returnStringFromNumber:(float)num
{
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setAllowsFloats:YES];

    NSString *str= [formatter stringFromNumber:[NSNumber numberWithFloat:num]];

    [formatter release];
    return str;
}

@end

Ответы [ 4 ]

4 голосов
/ 04 марта 2010

Поскольку ваша реализация StringNumber использует собственный объект NSNumberFormatter, а не тот, который вы создали в своем тестовом примере. Вам нужно выполнить классическую операцию рефакторинга, называемую «инверсия зависимостей», где ваш StringNumber объект принимает свой форматер в качестве параметра или ивара вместо того, чтобы создавать его внутренне. Затем вы можете передать имитатор форматирования как часть вашего теста.

1 голос
/ 08 мая 2010

Для примера кода, который вы представляете, я не буду беспокоиться о насмешках над NSNumberFormatter. Вы пытаетесь проверить, что [StringNumber returnStringFromNumber:] возвращает соответствующую строку. В этом случае вашему тесту не должно быть важно, какой метод он использует для вычисления этой строки, просто ваш метод работает так, как задумано.

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

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

Я склонен использовать насмешки, чтобы:

  • исключить зависимость, которая зависит от конкретной среды / конфигурации / набора данных
  • исключить зависимость, которая не будет работать во время теста
  • проверка поведения моего класса для различных случаев поведения зависимого кода (например, когда зависимость возвращает ноль, когда зависимость возвращает отрицательное значение, когда зависимость вызывает исключение и т. Д.)
0 голосов
/ 07 марта 2010

Еще одна идея: вы можете попробовать сделать ivar с форматером в классе StringNumber.Затем из ваших тестов можно будет установить значение форматера с помощью кодирования значения ключа.

С уважением, Квентин

0 голосов
/ 07 марта 2010

Вы можете попытаться динамически переопределить метод init NSNumberFormatter для возврата вашего фиктивного объекта.В ваших тестах вы должны сделать ivar из id mockFormatter.Таким образом, ваш метод тестирования становится следующим:

(void) testReturnStringFromNumber
{
    mockFormatter = [OCMockObject mockForClass:[NSNumberFormatter class]];
    StringNumber *testObject = [[StringNumber alloc] init];   

    [[mockFormatter expect] setAllowsFloats:YES];
    [testObject returnStringFromNumber:80.23456];
    [mockFormatter verify];
}

Затем вам нужно добавить категорию для класса NSNumberFormatter

@implementation NSNumberFormatter (mock)

- (id)init {
   id object;

   if (mockFormatter) {
      object = mockFormatter
   } else {
      object = invokeSupersequent();

   return object;
}

@end

Так что, когда в вашем тестируемом коде будет вызван метод init NSNumberFormatter,фиктивный объект будет использоваться, если вы его установили.

Источники: - http://cocoawithlove.com/2009/12/sample-mac-application-with-complete.html

С уважением, Квентин

...