如何在Kiwi中设置对模拟方法的参数预期

时间:2013-03-07 02:59:23

标签: objective-c tdd kiwi ocmockito ochamcrest

使用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];

在新西兰这样做是不是一种不那么笨拙的方式了?

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

1 个答案:

答案 0 :(得分: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];

这很好用,我发现它比间谍模式更容易实现。但是你的问题让我对expectations using message patterns感到疑惑。例如:

[[[aMockObject should] receive] doSomething:myArray];
[[[aMockObject should] receive] doSomething:any()];

第一个示例将验证aMockObject是否收到doSomething:消息,其参数为isEqual:myArray。第二个示例将简单地验证doSomething:是否已发送,而不期望阵列的争用。如果我们可以在消息模式中指定某种类型的Matcher,表示我们不关心消息中发送的特定数组实例,只是它的count为3。

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

  1. 文字对象值(例如上例中的myArray),与使用isEqual:的消息中发送的实际值进行比较
  2. KWAny类型的对象(例如上例中的any()宏),它将匹配任何参数值
  3. 满足[KWGenericMatchEvaluator isGenericMatcher:argumentFilter]的对象,这基本上意味着对象响应matches:(id)obj
  4. 因此,您应该能够在消息模式期望中使用实现matches:的对象来执行诸如验证发送到存根方法的数组长度之类的操作,而无需使用spys或blocks。这是一个非常简单的实现:( available as a 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的内置匹配器类会很好,但我还没有找到确切的方法。