我的代码调用了一个C库函数:
@implementation Store
...
-(void) doWork {
// this is a C function from a library
int data = getData();
...
}
end
我正在对上面的函数进行单元测试,我想在测试中模拟C函数
getData()
,这是我的测试用例:@interface StoreTests : XCTestCase {
int mData;
Store *store;
}
@end
@implementation StoreTests
-(void) setUp {
[super setUp];
mData = 0;
store = [[Store alloc] init];
}
-(void) testDoWork {
// this call will use the mocked getData(), no problem here.
[store doWork];
}
// mocked getData()
int getData() {
mData = 10; // Use of undeclared identifier 'mData', why?
return mData;
}
...
@end
为什么会出现编译器错误:
在
Use of undeclared identifier 'mData'
函数里面模拟了getData()
? 最佳答案
您误解了实例方法和变量的工作方式。
每个实例方法都有一个引用当前实例(或“当前对象”)的self
变量,并且实例变量(例如mData
)的使用是使用self
(例如self->mData
)访问该变量的简写,其中->
是(Objective-现场访问的C操作员。因此,您写成“长手”的setup
方法是:
-(void) setUp {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
但是对实例的引用
self
本身从哪里来?好吧,它不是神奇的,只是隐藏的,它会作为隐藏的额外参数自动传递给实例方法。此时切换到伪代码以显示此内容。您的setup
方法有效地编译为:-(void) setUp withSelf:(StoreTest *)self {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
和一个电话,例如:
StoreTests *myStoreTests = ...
[myStoreTests setup];
被有效地编译为:
[myStoreTests setup withSelf:myStoreTests];
自动添加额外的
self
参数。现在,以上所有内容仅适用于方法,并使它们能够访问实例变量和方法,不适用于普通C函数-它们没有隐藏的
self
参数,并且无法访问实例变量。您在添加的答案中提到的解决方案,该解决方案是在接口外部声明
mData
的:int mData;
@interface StoreTests : XCTestCase {
Store *store;
}
@end
将
mData
更改为全局变量,而不是实例变量。 C函数可以访问全局变量。但这确实意味着该类的每个实例共享相同的mData
,在这种情况下只有一个mData
,而不是每个实例一个。因此,将实例变量设置为全局变量并不是解决此类问题的通用解决方案,但是,由于您不太可能拥有多个
StoreTests
类实例,因此在这种情况下,这是一个合适的解决方案。但是,您应该进行一项更改:程序中只能有一个具有给定名称的全局变量,因此
mData
必须是唯一的,并且可以被程序中的任何代码访问,而不仅仅是StoreTests
的代码。您可以通过将变量声明为static
来减轻这种情况:static int mData;
这将变量保留为全局变量,但仅使其对声明中的同一文件中的代码可见,这可能只是
StoreTests
的代码。高温超导