Как установить ожидания по параметрам для смоделированных методов в киви

Используя OCMockito и OCHamcrest, я могу установить ожидания в отношении аргументов для смоделированных методов, таким образом:

[verify(aMockObject) doSomething:allOf(is(instanceOf([NSArray class])), hasCountOf(3U), nil)];

Кажется, не существует такого же простого способа сделать это с помощью киви. Можно захватить аргументы, используя шпиона, что-то вроде:

KWCaptureSpy *spy = [aMockObject captureArgument:@selector(doSomething:) atIndex:0];
NSArray *capturedArray = spy.argument;

А затем, чтобы проверить ожидания на захваченном объекте:

[[capturedArray should] haveCountOf:3U];

Есть ли менее неуклюжий способ сделать это на киви?

(Я знаю, что мог бы использовать здесь приспособления для подколенного сухожилия, но сейчас я изучаю, на что способен киви).

1 ответ

Решение

Один вариант, который я использовал, это 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: был отправлен, без ожидания о массиве arugment. Было бы замечательно, если бы мы могли указать некоторый тип Matcher в шаблоне сообщения, чтобы выразить, что нам все равно, какой конкретный экземпляр массива отправляется в сообщении, просто что он имеет count из 3.

Я не нашел примеров того, как это можно сделать, но похоже, что есть некоторые возможности. Чтобы проверить ожидание отправки сообщения, Kiwi использует KWMessagePattern класс, а именно matchesInvocation: а также argumentFiltersMatchInvocationArguments: методы. Это проверяет три типа "фильтров аргументов":

  1. Литеральные значения объекта (такие как myArray в приведенном выше примере), которые сравниваются с фактическим значением, отправленным в сообщении с использованием isEqual:
  2. Объект типа KWAny (такой как any() макрос в примере выше), который будет соответствовать любому значению аргумента
  3. Объекты, которые удовлетворяют [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, но я пока не выяснил, как именно это сделать.

Другие вопросы по тегам