describe(@"VVStack", ^{
context(@"when created", ^{
__block VVStack *stack = nil;
beforeEach(^{
stack = [VVStack new];
});
afterEach(^{
stack = nil;
});
it(@"should have the class VVStack", ^{
[[[VVStack class] shouldNot] beNil];
});
it(@"should exist", ^{
[[stack shouldNot] beNil];
});
it(@"should be able to push and get top", ^{
[stack push:2.3];
[[theValue([stack top]) should] equal:theValue(2.3)];
[stack push:4.6];
[[theValue([stack top]) should] equal:4.6 withDelta:0.001];
});
});
});

  看到这里的您看这段测试应该不成问题。需要注意的有两点:首先stack分别是在beforeEach和afterEach的block中的赋值的,因此我们需要在声明时在其前面加上__block标志。其次,期望描述的should或者shouldNot是作用在对象上的宏,因此对于标量,我们需要先将其转换为对象。Kiwi为我们提供了一个标量转对象的语法糖,叫做theValue,在做精确比较的时候我们可以直接使用例子中直接与2.3做比较这样的写法来进行对比。但是如果测试涉及到运算的话,由于浮点数精度问题,我们一般使用带有精度的比较期望来进行描述,即4.6例子中的equal:withDelta:(当然,这里只是为了demo,实际在这用和上面2.3一样的方法好了)。

  接下来我们再为这个context添加一个测试例,用来测试初始状况时栈是否为空。因为我们使用了一个Array来作为存储容器,根据我们之前用过的equal方法,我们很容易想到下面这样的测试代码
  it(@"should equal contains 0 element", ^{
  [[theValue([stack.numbers count]) should] equal:theValue(0)];
  });
  这段测试在逻辑上没有太大问题,但是有非常多值得改进的地方。首先如果我们需要将原来写在Extension里的numbers暴露到头文件中,这对于类的封装是一种破坏,对于这个,一种常见的做法是只暴露一个-count方法,让其返回numbers的元素个数,从而保证numbers的私有性。另外对于取值和转换,其实theValue的存在在一定程度上是破坏了测试可读性的,我们可以想办法改善一下,比如对于0的来说,我们有beZero这样的期望可以使用。简单改写以后,这个VVStack.h和这个测试可以变成这个样子:

 

//VVStack.h
//...
- (NSUInteger)count;
//...
//VVStack.m
//...
- (NSUInteger)count {
return [self.numbers count];
}
//...
it(@"should equal contains 0 element", ^{
[[theValue([stack count]) should] beZero];
});