// На основе класса смоделировать его экземпляр
id mockPerson = OCMClassMock([MOPerson class]);
// В соответствии с именем протокола смоделируйте реализованный протокол из экземпляра.
id mockProtocol = OCMProtocolMock(@protocol(MOTitleLineViewDelegate));
// Затемmockпротоколметод
// Выдает исключение при получении неожиданного метода
id strictMockClass = OCMStrictClassMock([MOPerson class]);
id strictMockProtocol = OCMStrictProtocolMock(@protocol(MOTitleLineViewDelegate));
Вот определение:Stub
,заглушка,то естьмоделированиефункция。
MOPerson *aPerson = [[MOPerson alloc] init];
id partialMockPerson = OCMPartialMock(aPerson);
вызовфункция:ужезаглушкаиз Просто активируйтезаглушкаиз(Stub
);еще нетзаглушкаиз Просто активируйте Исходный экземпляриз(aPerson
)。
Используйте официальныйизXCTNSNotificationExpectation
OCMStub([partialMockPerson name]).andReturn(@"moxiaoyan");
OCMStub([mock aMethodReturningABoolean]).andReturn(YES);
MOPerson *anotherPerson = [[MOPerson alloc] init];
// Другой объект из метода, сигнатура метода должна быть согласованной.
OCMStub([partialMockPerson name]).andCall(anotherPerson, @selector(name));
OCMStub([partialMockPerson name]).andDo(^(NSInvocation *invocation){
// При вызове метода name этот блок будет вызываться
// вызов будет содержать параметры метода
// вызов может установить возвращаемое значение
});
OCMStub([partialMock name]).andDo(nil);
Макетный объект будет вызывать этот блок при вызове функции. Этот блок может считывать параметры из вызывающего объекта и устанавливать возвращаемое значение.
OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation) {
/* block that handles the method invocation */
});
Возвращаемые значения через параметры:
// моделирование Должен вернуться из значения параметра
NSError *error = [NSError errorWithDomain:@"Не удалось получить друзей (заглушено)" code:001 userInfo:nil];
OCMStub([partialMockPerson loadFriendsWithError:[OCMArg setTo:error]]);
// вызов функции,Получить значение моделирования
NSError *resultError = nil;
[partialMockPerson loadFriendsWithError:&resultError];
NSLog(@"%@", resultError); // 001, Не удалось найти друзей (заморожено)
OCMStub([mock someMethodWithReferenceArgument:[OCMArg setToValue:OCMOCK_VALUE((int){aValue})]]);
Используйте то же самое 2.5.1.
// invokeBlockпо умолчаниюмоделирование,Все параметры являются значениями по умолчанию.
OCMStub([partialMockPerson deviceWithComplete:[OCMArg invokeBlock]]);
[partialMockPerson deviceWithComplete:^(NSString * _Nonnull value) {
NSLog(@"%@", value); // nil
}];
// invokeBlockWithArgsмоделирование,Значения параметров могут быть установлены
OCMStub([partialMockPerson deviceWithComplete:[OCMArg ignoreBlockWithArgs:@"iPhone"]]);
[partialMockPerson deviceWithComplete:^(NSString * _Nonnull value) {
NSLog(@"%@", значение // iPhone);
}];
При вызове функции настройки выдается исключение:
NSException *exception = [[NSException alloc] initWithName:@"Исключение при получении имени" причина:@"имя пусто" userInfo:nil];
OCMStub([partialMockPerson name]).andThrow(exception);
Функция настройки называется,уведомить(notify
)
NSNotification *notify = [NSNotification NotificationWithName:@"уведомить" object:self userInfo:nil];
OCMStub([partialMockPerson name]).andPost(notify);
Все операции, такие как andReturn и andPost, могут быть объединены в цепочку.
// моделированиеобъектбудет опубликованоуведомитьивозвращатьсяценить
OCMStub([mock someMethod]).andPost(aNotification).andReturn(aValue);
При использовании частично имитируемых экземпляров и имитируемых методов класса вы можете перенаправить заглушенные методы в реальный объект или класс. Это полезно только при объединении операций или использовании ожиданий.
OCMStub([partialMockPerson name]).andForwardToRealObject();
может бытьnil
вместо блока, переданного вandDo
。Это лишь частичномоделированиеилимоделированиедобрыйметод Иногда полезно。в этих случаях,использоватьandDo(nil)
эффективно подавлял существующиедобрыйсерединаиз Поведение。
OCMStub([mock someMethod]).andDo(nil);
Когда этот метод вызывается, ожидания среды XCTest оправдываются:
XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"XCTestизожидать"];
OCMStub([partialMockPerson name]).andFulfill(expectation);
OCMStub([partialMockPerson name]).andLog(@"%@", @"hehe");
позвони сюдаметодчас,format
проходитьNSLog
。Скорее всего, вы хотитесуществоватьцепьсерединаиспользоватьэто,может сопровождатьсяandReturn()
илиandForwardToRealObject()
OCMStub([partialMockPerson name]).andBreak();
При вызове этого метода отладчик открывается так, как если бы была достигнута точка останова. Стек будет в OCMock
из В стадии реализацииизгде-то закончиться,Но если вы посмотрите дальше,крест__forwarding__
рамка,вы должны иметь возможность видеть свойизкодпозвони сюдаметодиз Расположение。
[aPerson name];
OCMVerify([partialMockPerson name]);
проверятьname
был вызван тестовым кодом。нравиться Касаоеще нетпозвони сюдаметод,Будет сообщено об ошибке.
OCMStub([partialMockPerson name]).andReturn(@"momo");
[aPerson name];
OCMVerify([partialMockPerson name]);
Можно заглушить метод и при этом убедиться, что он был вызван.
Сколько раз вызывался метод проверки:
OCMVerify(atLeast(2), [partialMockPerson name]);
OCMVerify(never(), [partialMock doStuff]);
OCMVerify(times(0), [partialMock doStuff]);
OCMVerify(times(n), [partialMock doStuff]);
OCMVerify(atLeast(n), [partialMock doStuff]);
OCMVerify(atMost(n), [partialMock doStuff]);
// метод-заглушка, который может ответить на любой вызов
OCMStub([partialMockPerson addChilden:[OCMArg any]]); // Параметр — любой объект
OCMStub([partialMockPerson takeMoney:[OCMArg anyPointer]]); // Параметр — любой указатель
OCMStub([partialMockPerson changeWithSelector:[OCMArg anySelector]]); // Параметр — любой селектор
stub
метод,Могу ответитьнеобъект
параметризвызов(Могу ответитьпараметр Нетпроходитьизвызов:Илиобъектпараметр or необъектные параметры)
OCMStub([partialMockPerson setAge:0]).ignoringNonObjectArgs();
stub
метод,отвечать толькоСоответствие параметров
извызов
MOPerson *bPerson = [[MOPerson alloc] init];
OCMStub([partialMockPerson addChilden:bPerson]);
OCMStub([partialMockPerson addChilden:[OCMArg isNil]]);
OCMStub([partialMockPerson addChilden:[OCMArg isNotNil]]);
OCMStub([partialMockPerson addChilden:[OCMArg isNotEqual:bPerson]]);
OCMStub([partialMockPerson addChilden:[OCMArg isKindOfClass:[MOPerson class]]]);
вызовет anObject
из aSelector
метод и передать параметры в
в этомметодсерединасуждениепараметрлипроходить,проходить Сразу:возвращатьсяYES
, в противном случае:возвращатьсяNO
id anObject = nil;
SEL aSelector = @selector(addChilden:);
OCMStub([partialMockPerson addChilden:[OCMArg checkWithSelector:aSelector onObject:anObject]]);
OCMStub([partialMockPerson addChilden:[OCMArg checkWithBlock:^BOOL(id value) {
// Определите, проходит ли параметр, если он проходит: верните YES, В противном случае: верните НЕТ
return YES;
}]]);
OCMStub([partialMockPerson addChilden:startsWith(@"foo")]);
id mockPerson = OCMClassMock([MOPerson class]);
OCMStub([mockPerson mo_className]).andReturn(@"XXMOPerson");
// (1) Если в настоящее время нет метода экземпляра с таким же именем, метод класса mo_className может быть корректно Stubiz.
NSString *className1 = [MOPerson mo_className]; // XXMOPerson
// (2) Но если метод экземпляра имеет то же имя, что и он:
NSString *instanceName = [mockPerson mo_className]; // XXMOPerson
NSString *className2 = [MOPerson mo_className]; // class MOPerson
// Вам нужно использовать следующий метод для заглушки
OCMStub(ClassMethod([mockPerson mo_className])).andReturn(@"MOMOPerson");
NSString *className3 = [MOPerson mo_className]; // XXMOPerson
[mockPerson mo_className];
OCMVerify([mockPerson mo_className]);
[mockPerson stopMocking];
id partialMockPerson = OCMPartialMock(aPerson);
OCMStub([partialMockPerson mo_className]).andReturn(@"Partail Class");
NSString *partialName = [partialMockPerson mo_className]; // Partail Class
NSString *personName = [aPerson mo_className]; // Partail Class
[partialMockPerson mo_className];
OCMVerify([partialMockPerson mo_className]);
[partialMockPerson stopMocking];
id mockPerson = OCMClassMock([MOPerson class]);
OCMExpect([mockPerson addChilden:[OCMArg isNotNil]]);
[mockPerson addChilden:[MOPerson new]]; // Пока ни разу не ноль, проверка пройдена!
[mockPerson addChilden:nil];
OCMVerifyAll(mockPerson);
id strictPerson = OCMStrictClassMock([MOPerson class]);
[strictPerson mo_className]; // не ожидал этогометодизвызов,Значит тест провален
Вы также можете ожидатьизслучайиспользоватьandReturn
、andThrow
ждать。это будетсуществоватьвызовметодчасбегатьзаглушкадействовать,исуществоватьпроверятьчасубедиться, чтометодбыть реальнымвызов
OCMExpect([strictPerson mo_className]).andReturn(@"instance_MOPerson");
OCMExpect([strictPerson mo_className]).andThrow([NSException ...]);
[strictPerson mo_className];
OCMVerifyAll(strictPerson);
OCMExpect([strictPerson mo_className]);
[strictPerson mo_className];
OCMVerifyAllWithDelay(strictPerson, 3.0); // NSTimeInterval, Обычно возвращается, как только ожидания оправдываются
один развызов Этого достаточно?существовать“Ожидаемый список”серединаиз Следующийметод,моделированиебыстро потерпит неудачу и выдаст исключение。
[strictPerson setExpectationOrderMatters:YES];
OCMExpect([strictPerson mo_className]);
OCMExpect([strictPerson addChilden:[OCMArg any]]);
// Если порядок вызова неправильный, тест завершится неудачей.
[strictPerson mo_className];
[strictPerson addChilden:nil];
отOCMock 3.8
Не рекомендуется поначалуиспользоватьнаблюдательмоделирование。Пожалуйста, используйте вместо этогоXCTNSNotificationExpectation
strictмоделирование:вызовеще нетзаглушкаизметодвыдаст исключение Обычное моделирование: просто возвращает значение по умолчанию, функции можно настроить на быстрый сбой:
id mockPerson = OCMClassMock([MOPerson class]);
OCMReject([mockPerson mo_className]);
в этом случае,моделированиеприму всеметод,Кромеmo_className
,Если эта функция вызывается,Будет выброшено исключение.
в быстром режиме,Исключения не могут привести к сбою теста.(нравиться:когдаметодизвызовкучаеще нетсуществоватьтестсередина Заканчиватьчас)
OCMerifyAll
вызовчас,Исключение отказоустойчивости будет выброшено повторно.,Может обеспечить обнаружение звонков из уведомлений и т. д. без необходимости
MOPerson *myPerson = [[MOPerson alloc] init];
OCMStub([mockPerson copy]).andReturn(myPerson);
будет основано наметодимя,автоматическийвозвращатьсяобъектиз:alloc
、new
、copy
、mutableCopy
(количество ссылок)
Примечание: initметод не может выполнить заглушку.,Потому что это должнометодсделан измоделирование Реализовано само собойиз。 когдаinitметодбыл сновавызовчас,будет прямымвозвращаться
моделированиеобъектself
Таким образом, вы можете эффективно заглушить выделение и инициализацию.
MOPerson *person = [[MOPerson alloc] init];
id partialMockPerson = OCMPartialMock(person);
OCMStub([partialMockPerson mo_className]).andCall(myPerson, @selector(name));
методизимясказать Можетдругой,Но подпись должна быть та же самая
[mockPerson stopMocking];
[partialMockPerson stopMocking];
Запрещать без префиксаиз Макрос:ClassMethod()
、atLeast()
、…
Использовать префиксиз Макрос:OCMClassMethod()
、OCMAtLeast()
、…
некоторые рамкисуществоватьбегатьчасдинамическое изменениеобъектиздобрый。OCMock
Это сделано для реализации частимоделирование,иFoundation
Рамка изменитсядобрыйделатьдля(KVO
)механизмизчасть。
нравиться Без тщательной координации,может стать причиной несчастного случая Поведениеилиcrash
。
OCMock
ЗнатьKVO
,и будьте осторожны, чтобы избежать конфликта с
Для других фреймворков,OCMock
Предлагает только один отказмоделированиечтобы избежать несчастных случаев Поведениеизмеханизм
+ (BOOL)supportsMocking:(NSString **)reason {
*reason = @"Don't want to be mocked."
return NO;
}
проходить Реализуйте вышеизложенноеизметод,одиндобрый Можетвыбери не бытьMock
。
Когда разработчик пытается создать макет для этого класса, выдается исключение, объясняющее проблему, как сказано в
Допустимо, чтобы метод возвращал разные значения в отдельных вызовах, что позволяет ему реагировать на определенные условия во время выполнения.
нравиться Как и ожидалосьметоддляreason
наделятьценить,Возвращаемое значение будет игнорироваться
для всехеще нетреализовать этометодиздобрый,OCMock
Предположим, это приемлемоMock
Определите, является ли объект частичного моделирования
BOOL isPartialMockObj = OCMIsSubclassOfMockClass(objc_getClass(partialMockPerson));
Не делайте этого:
id mock1 = OCMClassMock([SomeClass class]);
OCMStub([mock1 aClassMethod]);
id mock2 = OCMClassMock([SomeClass class]);
OCMStub([mock2 anotherClassMethod]);
нравиться Если добавленозаглушкадобрыйметодизмоделированиеобъектеще нетвыпускать,нозаглушкаметодбудет сохраняться,Несмотря на тосуществоватьтестсередина Слишкомнравитьсяэтот。нравитьсянесколько фруктовмоделированиеобъекттакой жечасдействоватьтакой же一добрый,Поведение будет непредсказуемым.
id mock = OCMStrictClassMock([SomeClass class]);
OCMStub([mock someMethod]).andReturn(@"a string");
OCMExpect([mock someMethod]);
потому чтокогдапонял раньшемоделированиеобъектизметод,Stub
Справлюсь со всем для этогоизвызов。意味着Несмотря на товызов Пришло времяметод,Проверка также не пройдет
Чтобы избежать этой проблемы:
andReturn
существоватьExpect
заявлениесерединадобавить вid partialMockForString = OCMPartialMock(@"Foo"); // выдаст исключение
NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];
id partialMockForDate = OCMPartialMock(date); // Повлияет ли это на некоторые структуры?
не в состоянии toll-free bridged
добрыйизсоздание экземпляра локальномоделирование
не в состоянии Определенные создания экземпляров представлены помеченными указателями.изобъект,нравиться:NSString
、на некоторых архитектурах、NSDate
на некоторых архитектурах
id partialMockForString = OCMPartialMock(anObject);
OCMStub([partialMock class]).andReturn(someOtherClass); // will not work
Не могущиймоделирование许多核心бегатьчасметод。включать:init
、class
、methodSignatureForSelector:
、forwardInvocation:
、respondsToSelector
ждатьждать
// Невозможно вступить в силу, метод не будет заглушен.
id stringMock = OCMClassMock([NSString class]);
// Невозможно заглушить методы класса проверки в NSString и NSArray. Попытка сделать это не имеет никакого эффекта.
OCMStub([stringMock stringWithContentsOfFile:[OCMArg any] encoding:NSUTF8StringEncoding error:[OCMArg setTo:nil]]);
// Невозможно вступить в силу, метод не будет заглушен.
id mock = OCMClassMock([MyManagedObject class]);
// Невозможно заглушить методы класса проверки в NSManagedObject и его подклассах. Попытка сделать это не имеет никакого эффекта.
OCMStub([mock someClassMethod]).andReturn(nil);
id mock = OCMClassMock([NSObject class]);
/* run code under test, which calls awakeAfterUsingCoder: */
OCMVerify([mock awakeAfterUsingCoder:[OCMArg any]]); // still fails
Невозможно использовать в NSObject
Реализуйте метод из или на нем и категорию из для проверки после запуска.
В некоторых случаях можно заглушить метод, а затем проверить его.
Проверка после выполнения может использоваться, когда метод переопределяется в подклассе.
UIWindow *window = /* get window somehow */
id mock = OCMPartialMock(window);
/* run code under test, which causes _sendTouchesForEvent: to be invoked */
OCMVerify([mock _sendTouchesForEvent:[OCMArg any]]); // still fails
Невозможно в корне Apple
Используйте частные методы в классе для проверки после запуска.
В частности, в NS
или UI
Как и в классе с префиксом из, все методы начинаются с подчеркивания и заканчиваются суффиксом /илииз.
В некоторых случаях можно заглушить метод, а затем проверить его.
в настоящий момент Не могущийпроверять Есть задержкаизметод。这в настоящий момент只能использоватьподсуществоватьстрогиймоделированиеи ожиданиясерединаописыватьизexpect-run-verify
метод。
OCMock
Не полностью потокобезопасен. до 3.2.x Версия OCMock
Нисколько Знатьнить。из нескольких темизмоделированиеобъектначальствоизлюбойдействовать组合都可能导致问题и使тест失败
от OCMock 3.3
Для начала вам все равно понадобится один поток для вызова всех операций настройки и проверки, желательно основной поток запуска теста.
но,Можетот多个нитьиспользоватьмоделированиеобъект。моделированиеобъектдаже Можетсуществоватьдругойизнитьсерединаиспользовать,При этом его настройка продолжается в основном потоке.
mock
не может быть напрямуюmock
Синглтониз,вызоветmock
конфликт。
Рекомендуемый способ записи:
// издеваться каждый раз alloc синглтон
id center = OCMPartialMock([[QLLoginCenter alloc] init]);
// mock этоиз sharedInstance метод
OCMStub([[center classMethod] sharedInstance]).andReturn(center);
ссылка:OCMock Demo:адрес GitHub