2013-07-29 42 views
4

我终于强加了一些TDD在我正在处理的一个项目上,并跑到边缘......我知道我想要的代码,但不知道如何测试吧:)OCMock测试一个对象被分配,并调用它的一个方法

我在寻找的实现是:

- (void) doSomething 
{ 
    FooBuilder *foo = [[FooBuilder alloc] init]; 
    [foo doSomethingElseWithCompletionBlock:^{ 
     [self somethingDone]; 
    }]; 
} 

所以我想我的测试来验证)测试方法分配一个新的FooBuilder和b)该方法然后调用新对象的一种方法。

我该如何解决这个问题?我开始尝试嘲笑类方法,但很快就确定了这条路是疯狂的。

注意我没有在这个测试中测试FooBuilder本身,只是在那里进行了合作。

回答

1

通常情况下,依赖注入被用来提供一个完整的对象,说“而不是要求这个对象,在这里你去使用这个。”但在这种情况下,我们希望能够实例化一个新对象。所以我们不需要注入一个对象,而是注入这个类。 “而不是创建一个特定的类,在这里你去实例化其中的一个。”

有两种主要的依赖注入形式:“构造函数注入”(即使Objective-C将其分解为分配和初始化)和“属性注入”,我会坚持使用“构造函数”一词。

对于构造函数注入,指定类在初始化:

- (instancetype)initWithFooBuilderClass:(Class)fooBuilderClass; 

对于财产注射,指定类的属性:

@property (nonatomic, strong) Class fooBuilderClass; 

构造方法注入更清晰,因为它使依赖明显。但你可能更喜欢财产注入。有时我开始一种方式,重新思考另一种方式,改变我的想法。

无论使用哪种方式,您都可以使用默认初始值设定项,该默认初始值设定项将-initWithFooBuilderClass:或将属性设置为[FooBuilderClass class]

然后doSomething应该像这样开头:

- (void)doSomething 
{ 
    id foo = [[self.fooBuilderClass alloc] init]; 
    ... 
+0

乔恩,感谢您的关注和详细的回复 - 但我想我在这里错过了一些东西。你诊断被测试的类和'FooBuilder'类之间的耦合是问题。在这样做的过程中,我觉得你正在简化更复杂的事情。我有一个显示Foos的对象Bar;要做到这一点,它需要用FooBuilder构建一个Foo。我觉得你要求我介绍一般性,我不需要仅仅为了简化测试。 – dpassage

+0

我今天早上醒来意识到问题实际上只是一个类的依赖注入。所以我完全重写了我的答案。试试它的大小。 ...如果它仍然感觉过于复杂,让我知道,我会尝试进一步解释。 –

+0

我仍然认为你没有得到我所要求的。我的问题是如何驱动OCMock API以确保我的被测对象正在进行正确的出站调用。你仍然试图将普遍性注入一个不需要它的类中。 – dpassage

0

我最终加入了一类新的方法来FooBuilder这需要完成块作为参数解决该问题。所以我已经将实例化和方法调用从我的被测对象中移出到了协作者对象中。现在我可以嘲笑那个单一的类方法调用。

我认为这最终会比我刚开始时的设计略好;现在需要有一个新的FooBuilder实例化的细节对类的用户是隐藏的。这也很简单。

它确实具有保持我的被测对象和FooBuilder类之间强大耦合的特性。也许这会让我陷入困境 - 但我正在让YAGNI打赌它不会。

+0

我很高兴你发现有效的东西。但是你会在其他地方遇到同样的问题,并需要借助依赖注入。我在这里给出另一个DI例子:http://stackoverflow.com/questions/13711911/unit-testing-example-with-ocunit/ –

+0

我相信我会的,这是一个很好的技术知道。但是,在这种情况下,它真的感觉就像增加了一般性会使代码更难理解。感谢您的帮助 - 我已经在我的应用中使用了来自您网站的一些提示:) – dpassage

相关问题