【问题标题】:Strange ordering of Kiwi iOS context blocksKiwi iOS 上下文块的奇怪排序
【发布时间】:2013-04-12 23:00:42
【问题描述】:

我有一个看起来像这样的 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] 行是在测试失败之前执行的。我感觉我可能误解了块的执行顺序。

任何建议将不胜感激!

【问题讨论】:

  • 您不需要在collectionobject 上使用__block,因为您不会在任何地方分配给任何一个
  • 你是对的 - 我已经编辑了我的问题。当我改变它时,我仍然看到相同的行为。
  • 我对 Kiwi 了解不多,但您确定 [collection shouldNotBeNil]; 是正确的吗?如果collectionnil 它只是nop
  • shouldNotBeNil 是 Kiwi 库的标准部分,但我可以看出它看起来可能会产生误导。请注意,这不是一个普通的方法调用——它实际上是一个宏,最终将期望类型添加到规范对象。所以它实际上并没有将消息传递给潜在的 nil 对象。如果您想仔细查看,可以在这里查看 Kiwi 的所有源代码? - github.com/allending/Kiwi
  • 另外,您可以取消您的shouldNotBeNil 检查并用更简单的[[collection.objects should] haveCountOf:integer] 替换计数检查。 haveCountOf: 消息不需要使用theValue,您将其传递给一个标量整数。由于should 将隐式断言collection.objects 不是nil(因此如果collection 本身为nil 也会失败),即使在检查计数为零。

标签: ios objective-c bdd objective-c-blocks kiwi


【解决方案1】:

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

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

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

解决方案

使用__block 修饰符声明collection,并使用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 对象引用可以通过所有这些块函数正确保留和修改。

【讨论】:

  • 这个解释真的很有帮助!我现在认为context/describe 块只是逻辑分隔符,任何代码都需要位于其他类型的 Kiwi 块中。感谢您提供所有信息 - 非常感谢!
猜你喜欢
  • 2023-03-05
  • 1970-01-01
  • 2013-09-20
  • 2014-11-08
  • 1970-01-01
  • 2011-03-13
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
相关资源
最近更新 更多