2013-10-10 4 views
4

Я знаю, что OCMock версии 2.1+ supports методы класса stubbing из коробки. Но почему-то это не работает со мной. Для того, чтобы убедиться, что я выделил проблему, я просто клонировали пример OCMock project (который четко обозначена как версия 2.2.1) и просто добавили это внутри testMasterViewControllerDeletesItemsFromTableView:не может использовать метод класса-заглушки с OCMock 2.1+ в Xcode 5.0

id detailViewMock = [OCMockObject mockForClass:[DetailViewController class]]; 
[[[detailViewMock stub] andReturn:@"hello"] helloWorld]; 

в DetailViewController.h я добавил:

+ (NSString *)helloWorld; 

и DetailViewController.m:

+ (NSString *)helloWorld { 
    return @"hello world"; 
} 

Но я продолжаю получать ошибки:

*** -[NSProxy doesNotRecognize Selector:helloWorld] called! 

Чтобы увидеть демонстрацию проблемы, пожалуйста, clone this repo, чтобы посмотреть, что происходит.

+0

Похоже, что он должен работать ... Предполагаю, что DetailViewController.h включен в ваш тест? Можете ли вы назвать «helloWorld» без использования mocks? –

+0

yes 'DetailViewController.h' включен в тест и заменен заглушкой метода класса с регулярным заглушкой (та же самая мировая подпись и т. Д.) .. и это не сработало .. – abbood

+0

@BenFlynn Я просто создал очень простой [ repo] (https://github.com/abbood/very-simple-oc-mock-stub-example/blob/master/verySimpleOCMockStubExampleTests/otherTests.m) для демонстрации проблемы, которую я получаю. Если вы можете взять быстро заглянуть, что было бы здорово! – abbood

ответ

4

Это должно работать нормально. Я просто попытался в моем проекте, который использует XCTest на Xcode5, и этот код прошел.

Я бы 1) убедитесь, что вы используете последнюю версию OCMock (которая сейчас 2.2.1, я думаю, что есть некоторые исправления как для методов класса, так и для Xcode5 в более новых версиях) и 2) убедитесь, что ваш класс DetailViewController правильно связан в среде выполнения (то есть в части правильной цели).

Рассматривая свой проект, ваш класс DetailViewController является частью основного приложения, и контрольной целью.С Xcode5 кажется, что это означает, что две копии класса компилируются и присутствуют во время выполнения, с кодом в приложении, вызывающим одну копию, и кодом в тестовом случае, вызывающим другое. Раньше это была ошибка компоновщика (дубликаты символов), но, к лучшему или худшему, теперь компоновщик теперь молчаливо разрешает существование двух экземпляров того же класса (с тем же именем) в среде выполнения ObjC. OCMock, используя динамический поиск, находит первый (тот, который скомпилирован в приложение), но тестовый пример напрямую связан со второй копией (той, которая скомпилирована в тестовый комплект). Итак ... OCMock на самом деле не насмехается над классом, который, как вы думаете.

Вы можете видеть это, только для усмешек, проверив как часть тестового примера, что класс [DetailViewController] не будет равен NSClassFromString (@ «DetailViewController») (первый напрямую связан, второй - динамический).

Чтобы исправить это правильно, в «Целевом членстве» для DetailViewController.m просто снимите контрольную цель. Таким образом, во время выполнения есть только одна копия класса, и все работает так, как вы ожидали. Комплект тестирования загружается в основное приложение, поэтому все классы основного приложения должны быть доступны для пакета без необходимости их непосредственного компиляции в пакет. Классы должны быть только частью одной из двух целей, а не обоими (это всегда было так).

+0

После такого длинного ответа я должен спросить: вы попробовали свое решение на предоставленном мной репо? Я просто дважды проверил и убедился, что 'DetailViewController' действительно является частью самой цели приложения и * не * частью цели тестирования. Я также проверил, является ли класс [DetailViewcontroller] равным NSClassFromString (@" DetailViewController "). и, конечно же, они (они оба возвращают строки в любом случае .., которые не говорят много) короче .. ваш ответ не работал – abbood

+0

Да, я скачал ваш проект. DetailViewController был частью обеих целей; как только я удалил его из тестовой цели, пройденной тестом. Однако у меня установлен новый OCMock. Что касается equals, я имел в виду, что [DetailViewController class] (при вызове из тестового примера) не будет возвращать тот же указатель, что и NSClassFromString (@ «DetailViewController») - если вы сравните их с «==», они не совпадают в ваш проект, тогда как обычно они должны быть. –

+0

Даже глядя на ваш скриншот выше, я вижу «Скомпилировать источники (2 элемента)», когда выбран целевой тест - один из них - ваш файл otherTests.m; второй - DetailViewController.m. В этом скриншоте должен быть только один элемент; DetailViewController должен отображаться только в области «Компиляция источников», когда выбран целевой объект. –

2

Не могли бы вы показать код, который вы тестируете? Это работает:

@interface DetailViewController : UIViewController 

+ (NSString *) helloWorld; 

@end 

@implementation DetailViewController 

+ (NSString *)helloWorld 
{ 
    return @"hello world"; 
} 

@end 

Тест:

- (void) test__stubbing_a_class_method 
{ 
    id mockDetailViewController = [OCMockObject mockForClass:[DetailViewController class]]; 
    [[[mockDetailViewController stub] andReturn:@"hello"] helloWorld]; 

    STAssertEqualObjects([DetailViewController helloWorld], @"hello", nil); 
} 
+0

ваш ответ вдохновил меня найти правильный. +1 :) – abbood

+0

Я просто создал очень простой [репо] (https://github.com/abbood/very-simple-oc-mock-stub-example/blob /master/verySimpleOCMockStubExampleTests/otherTests.m) для демонстрации проблемы, которую я получаю. Если вы можете быстро взглянуть, это было бы здорово! – abbood

1

Хотя Carl Lindberg's ответ является correct one, я понял, я бы подвести итог, что мы обсуждали в комментариях свой ответ здесь:

  • Проблема состояла в том, что я использовал устаревшую версию OCMock . Причина, по которой я туда попал, - это b/c, инструкции на страницепросто попросили меня взять пример iOS с их учетной записи github и скопировать библиотеку OCMock (им даже поручено использовать ту же структуру каталогов). Получается, что библиотека в их примере over 2 years old!!.

  • Чтобы исправить это, просто запустите сценарий build.rb на оболочке, например: ruby build.rb. Это даст вам последнюю библиотеку libOCMock.a, которую вы можете просто подключить к своему проекту и Voila! это все!

+1

Или используйте Cocoapods! Версия 2.3.3 отлично работает с Xcode 5 и iOS 7 и XCTest. Там довольно удачи. –

0

просто использовать

id detailViewMock = [OCMockObject niceMockForClass:[DetailViewController class]]; 
+0

не работал, к сожалению, – abbood

1

Глядя на ваш образец проекта:

  1. Вы не должны компилировать DetailViewController.m в тестовой мишени.

  2. У вас не должно быть никаких ссылок на OCMock в вашей основной цели.

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