我使用的一个选项是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 收到带有 isEqual:myArray 参数的 doSomething: 消息。第二个示例将简单地验证 doSomething: 是否已发送,而不需要数组参数。如果我们可以在消息模式中指定某种类型的 Matcher 那就太好了,以表示我们不关心消息中发送的是什么特定的数组实例,只关心它的 count 为 3。
我还没有找到任何能够做到这一点的例子,但看起来有一些可能性。为了验证消息发送期望,Kiwi 使用KWMessagePattern 类,特别是matchesInvocation: 和argumentFiltersMatchInvocationArguments: 方法。这会检查三种类型的“参数过滤器”:
- 文字对象值(如上例中的
myArray),与使用isEqual:在消息中发送的实际值进行比较
-
KWAny 类型的对象(如上例中的 any() 宏),它将匹配任何参数值
- 满足
[KWGenericMatchEvaluator isGenericMatcher:argumentFilter]的对象,基本表示对象响应matches:(id)obj
因此,您应该能够使用在消息模式期望中实现matches: 的对象来执行诸如验证发送到存根方法的数组长度之类的事情,而无需求助于间谍或块。这是一个非常简单的实现:(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 的内置匹配器类会很好,但我还没有确切地知道如何做到这一点。