我正在为一个Foo
课程编写单元测试,该课程有一个合作者Bar
。我想在Bar
的测试中使用Foo
的手动构建的存根实现。
如果我在Java中这样做,我会给Foo
一个BarFactory
合作者并在MockBarFactory
的{{1}}测试中注入一个总是返回{{1} }}
我知道这种技术在Objective-C中运行良好,但它并没有让我觉得在动态语言中这是一个特别惯用的事情。我想知道我是否可以做任何棘手的事情,这会导致Foo
在我运行单元测试时返回StubBar
,但在“现实生活”中给我[[Bar alloc] init]
的正常实现。
或者明显的工厂模式在这种情况下最适合使用?
答案 0 :(得分:1)
您可以在init
中返回其他对象。这就是为什么你应该将[super init]
的返回值分配给self
。尝试这样的事情:
@implementation Bar
- (id)init {
if (UNIT_TEST) {
self = [[StubBar alloc] init];
if (self) {
// do unit test init here
}
} else {
self = [super init];
if (self) {
// do regular init here
}
}
return self;
}
...
@end
注意:这应该在ARC下工作。如果您不使用ARC,请确保在分配新的self
实例之前发布StubBar
。
@implementation Bar
- (id)init {
#if UNIT_TEST
self = [[StubBar alloc] init];
if (self) {
// do unit test init here
}
#else
self = [super init];
if (self) {
// do regular init here
}
#endif
return self;
}
...
@end
如果您想完全分离单元测试和实际代码,您可以只有两个不同版本的Bar
类。一个将使用真实代码编译,另一个将使用单元测试目标。
您可以轻松地分配实例,而无需在编译时知道确切的类类型,如下所示:
id someBar = [[someClass alloc] init]; // assuming someClass is of type Class
或:
id someBar = [[NSClassFromString(@"Bar") alloc] init];
第一个是优选的。你可以使用它来拥有一个默认的类类型,你可以在进行单元测试时改变它。作为Foo
本身的属性,或者在单元测试时重新定义的预处理器宏。
答案 1 :(得分:0)
您正在寻找的是OCMock的内容。 它允许您从类,协议和特别是单元测试中构建模拟对象。