更进一步地,对于一个collection来说,Kiwi有一些特殊处理,比如have和haveCountOf系列的期望。如果测试的对象实现了-count方法的话,我们可以使用这一系列期望来写出更好的测试语句。比如上面的测试还可以进一步写成
  it(@"should equal contains 0 element", ^{
  [[stack should] haveCountOf:0];
  });
  在这种情况下,我们并没有显式地调用VVStack的-count方法,所以我们可以在头文件中将其删掉。但是我们需要保留这个方法的实现,因为测试时是需要这个方法的。如果测试对象不能响应count方法的话,如你所料,测试时会扔一个unrecognized selector的错。Kiwi的内部实现是一个大量依赖了一个个行为Matcher和objc的消息转发,对objcruntime特性比较熟悉,并想更深入的朋友不放可以看看Kiwi的源码,写得相当漂亮。
  其实对于这个测试,我们还可以写出更漂亮的版本,像这样:
  it(@"should equal contains 0 element", ^{
  [[stack should] beEmpty];
  });
  好了。关于空栈这个情景下的测试感觉差不多了。我们继续用TDD的思想来完善VVStack类吧。栈的话,我们当然需要能够-pop,也是说在(Given)给定一个栈时,(When)当栈中有元素的时候,(Then)我们可以pop它,并且得到栈顶元素。我们新建一个context,然后按照这个思路书写行为描述(测试):

 

context(@"when new created and pushed 4.6", ^{
__block VVStack *stack = nil;
beforeEach(^{
stack = [VVStack new];
[stack push:4.6];
});
afterEach(^{
stack = nil;
});
it(@"can be poped and the value equals 4.6", ^{
[[theValue([stack pop]) should] equal:theValue(4.6)];
});
it(@"should contains 0 element after pop", ^{
[stack pop];
[[stack should] beEmpty];
});
});

  完成了测试书写后,我们开始按照设计填写产品代码。在VVStack.h中完成申明,并在.m中加入相应实现。
  - (double)pop {
  double result = [self top];
  [self.numbers removeLastObject];
  return result;
  }
  很简单吧。而且因为有测试的保证,我们在提供像Stack这样的基础类时,不需要等到或者在真实的环境中检测了。因为在被别人使用之前,我们自己的测试代码已经能够保证它的正确性了。VVStack剩余的后一个小问题是,在栈是空的时候,我们执行pop操作时应该给出一个错误,用以提示空栈无法pop。虽然在objc中异常并不常见,但是在这个情景下是抛异常的好时机,也符合一般C语言对于出空栈的行为。我们可以在之前的“when created”上下文中加入一个期望:
  it(@"should raise a exception when pop", ^{
  [[theBlock(^{
  [stack pop];
  }) should] raiseWithName:@"VVStackPopEmptyException"];
  });
  和theValue配合标量值类似,theBlock也是Kiwi中的一个转换语法,用来将一段程序转换为相应的matcher,使其可以被施加期望。这里我们期望空的Stack在被pop时抛出一个叫做”VVStackPopEmptyException”的异常。我们可以重构pop方法,在栈为空时给一个异常:

 

- (double)pop {
if ([self count] == 0) {
[NSException raise:@"VVStackPopEmptyException" format:@"Can not pop an empty stack."];
}
double result = [self top];
[self.numbers removeLastObject];
return result;
}

  进一步的Kiwi
  VVStack的测试和实现到这里吧,根据这套测试,您可以使用自己的实现来轻易地重构这个类,而不必担心破坏它的公共接口的行为。如果需要添加新的功能或者修正已有bug的时候,我们也可以通过添加或者修改相应的测试,来确保正确性。我将会在下一篇博文中继续介绍Kiwi,看看Kiwi在异步测试和mock/stub的使用和表现如何。Kiwi现在还在比较快速的发展中,官方repo的wiki上有一些不错的资料和文档,可以参考。VVStack的项目代码可以在这个repo上找到,可以作为参考。