3

我有一个看起来像这样的 Kiwi 规范文件:

#import "Kiwi.h"
#import "MyCollection.h"

SPEC_BEGIN(CollectionSpec)

describe(@"Collection starting with no objects", ^{
    MyCollection *collection = [MyCollection new];

    context(@"then adding 1 object", ^{
        MyObject *object = [MyObject new];
        [collection addObject:object];
        it(@"has 1 object", ^{
            [collection shouldNotBeNil];
            [collection.objects shouldNotBeNil];
            [[theValue(collection.objects.count) should] equal:theValue(1)]; //failing test
        });

        context(@"then removing 1 object", ^{
            [collection removeObject:object];
            it(@"has 0 objects", ^{
                [[theValue(collection.objects.count) should] equal:theValue(0)]; //passing test
            });
        });
    });
});

SPEC_END

运行规范会导致这行代码出现一次失败[[theValue(collection.objects.count) should] equal:theValue(1)];

这是奇怪的部分 - 如果我从规范中删除整个context(@"then removing 1 object", ^{...})块,则上述测试通过。

这让我相信这[collection removeObject:object]条线在测试失败之前就被执行了。我有一种感觉,我可能误解了块的执行顺序。

任何建议,将不胜感激!

4

1 回答 1

10

你是正确的,[collection removeObject:object]在失败的测试之前被执行。将 Kiwi 测试视为分两次运行:

  1. 设置:测试文件中的代码从上到下执行以设置测试上下文和期望
  2. 执行:运行每个单元测试,基本上每个it/specify语句一个,为每个测试重复正确的设置/拆卸代码

请注意,Kiwi 测试文件中的大部分代码都指定为发送到 Kiwi 函数的一系列块。任何不遵循 Kiwi 块模式的代码,例如初始化/修改collection变量的代码,都可能因此在意外时间执行。在这种情况下,所有的集合修改代码都在设置测试的第一遍期间执行,然后运行您的测试。

解决方案

collection使用__block修饰符声明,并用于beforeEach实例化和修改collection对象:

describe(@"Collection starting with no objects", ^{
    __block MyCollection *collection;
    beforeEach(^{
        collection = [MyCollection new];
    });

    context(@"then adding 1 object", ^{
        beforeEach(^{
            MyObject *object = [MyObject new];
            [collection addObject:object];
        });
        it(@"has 1 object", ^{
            ...
        });

        context(@"then removing 1 object", ^{
            beforeEach(^{
                [collection removeObject:object];
            });
            it(@"has 0 objects", ^{
                ...

这些beforeEach块告诉 Kiwi 在每个单元测试中专门运行一次给定的代码,并且使用嵌套上下文,这些块将根据需要按顺序执行。所以 Kiwi 会做这样的事情:

// run beforeEach "Collection starting with no objects"
collection = [MyCollection new]
// run beforeEach "then adding 1 object"
MyObject *object = [MyObject new]
[collection addObject:object]
// execute test "has 1 object"
[collection shouldNotBeNil]
[collection.objects shouldNotBeNil]
[[theValue(collection.objects.count) should] equal:theValue(1)]

// run beforeEach "Collection starting with no objects"
collection = [MyCollection new]
// run beforeEach "then adding 1 object"
MyObject *object = [MyObject new]
[collection addObject:object]
// run beforeEach "then removing 1 object"
[collection removeObject:object]
// execute test "has 0 objects"
[[theValue(collection.objects.count) should] equal:theValue(0)]

修改器将__block确保collection可以通过所有这些块函数正确保留和修改对象引用。

于 2013-04-14T22:50:54.473 回答