Один из вариантов, который я использовал, это stub:withBlock:
NSArray* capturedArray; // declare this as __block if needed
[aMockObject stub:@selector(doSomething:)
withBlock:^id(NSArray *params) {
capturedArray = params[0];
// this is necessary even if the doSomething method returns void
return nil;
}];
// exercise your object under test, then:
[[capturedArray should] haveCountOf:3U];
Это прекрасно работает, и мне кажется, что его проще реализовать, чем шпионский шаблон. Но ваш вопрос заставил меня задуматься об ожиданиях при использовании шаблонов сообщений. Например:
[[[aMockObject should] receive] doSomething:myArray];
[[[aMockObject should] receive] doSomething:any()];
В первом примере проверяется, что aMockObject
получил сообщение doSomething:
с аргументом, который isEqual:myArray
. Второй пример просто проверит, что doSomething:
было отправлено, не ожидая аргумента массива. Было бы здорово, если бы мы могли указать какой-либо тип Matcher в шаблоне сообщения, чтобы показать, что нам все равно, какой конкретный экземпляр массива отправляется в сообщении, только то, что он имеет count
из 3.
Я не нашел примеров того, как это сделать, но похоже, что есть некоторые возможности. Чтобы проверить ожидание отправки сообщения, Kiwi использует класс KWMessagePattern
, а именно методы matchesInvocation:
и argumentFiltersMatchInvocationArguments:
. Это проверяет три типа «фильтров аргументов»:
- Буквенные значения объекта (например,
myArray
в приведенном выше примере), которые сравниваются с фактическим значением, отправленным в сообщении с использованием isEqual:
.
- Объект типа
KWAny
(например, макрос any()
в приведенном выше примере), который будет соответствовать любому значению аргумента.
- Объекты, которые удовлетворяют
[KWGenericMatchEvaluator isGenericMatcher:argumentFilter]
, что в основном означает, что объект отвечает на matches:(id)obj
Таким образом, вы должны иметь возможность использовать объекты, которые реализуют matches:
в ожиданиях шаблона сообщения, чтобы делать такие вещи, как проверка длины массивов, отправляемых в заглушки, не прибегая к шпионам или блокам. Вот очень простая реализация: (доступно как Gist)
// A reusable class that satisfies isGenericMatcher:
@interface SOHaveCountOfGenericMatcher : NSObject
- (id)initWithCount:(NSUInteger)count;
- (BOOL)matches:(id)item; // this is what KWMessagePattern looks for
@property (readonly, nonatomic) NSUInteger count;
@end
@implementation SOHaveCountOfGenericMatcher
- (id)initWithCount:(NSUInteger)count
{
if (self = [super init]) {
_count = count;
}
return self;
}
- (BOOL)matches:(id)item
{
if (![item respondsToSelector:@selector(count)])
return NO;
return [item count] == self.count;
}
@end
// Your spec:
it(@"should receive an array with count 3", ^{
NSArray* testArray = @[@"a", @"b", @"c"];
id argWithCount3 = [[SOHaveCountOfGenericMatcher alloc] initWithCount:3];
id aMockObject = [SomeObj nullMock];
[[[aMockObject should] receive] doSomething:argWithCount3];
[aMockObject doSomething:testArray];
});
Было бы неплохо иметь возможность повторно использовать здесь встроенные классы сопоставления Kiwi, но я еще не выяснил, как именно это сделать.
person
Mike Mertsock
schedule
28.03.2013