2

使用 OCMockito 和 OCHamcrest,我可以对模拟方法的参数设置期望,因此:

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

使用 Kiwi 似乎没有同样简单的方法可以做到这一点。可以使用间谍来捕获参数,例如:

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

然后检查对捕获对象的期望:

[[capturedArray should] haveCountOf:3U];

在 Kiwi 中是否有一种不那么笨拙的方法来做到这一点?

(我知道我可能可以在这里使用 hamcrest 匹配器,但目前我正在探索 Kiwi 的能力)。

4

1 回答 1

4

我使用的一个选项是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 那就太好了,以表示我们不在乎在消息中发送什么特定的数组实例,只关心它的 acount为 3。

我还没有找到任何能够做到这一点的例子,但看起来有一些可能性。为了验证消息发送期望,Kiwi 使用KWMessagePattern类,特别是matchesInvocation:andargumentFiltersMatchInvocationArguments:方法。这将检查三种类型的“参数过滤器”:

  1. 文字对象值(如myArray上面的示例中),与消息中发送的实际值进行比较,使用isEqual:
  2. 一个类型的对象KWAnyany()例如上面示例中的宏),它将匹配任何参数值
  3. 满足[KWGenericMatchEvaluator isGenericMatcher:argumentFilter]的对象,这基本上意味着对象响应matches:(id)obj

因此,您应该能够使用matches:在消息模式期望中实现的对象来执行诸如验证发送到存根方法的数组长度之类的事情,而无需求助于 spys 或块。这是一个非常简单的实现:(作为 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 的内置匹配器类会很好,但我还没有确切地知道如何做到这一点。

于 2013-03-28T03:04:22.113 回答