我的代码调用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()
函数吗?
答案 0 :(得分:1)
您误解了实例方法和变量的工作原理。
每个实例方法都有一个引用当前实例(或“当前对象”)的变量self
,并且使用实例变量(例如mData
)是使用{访问该变量的简写{1}},例如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];
参数。
现在以上所有内容仅适用于方法,并使它们能够访问实例变量和方法,它不适用于普通的C函数 - 它们没有隐藏的self
参数,也不能访问实例变量。
您在答案中提到的在界面外声明self
的解决方案:
mData
将int mData;
@interface StoreTests : XCTestCase {
Store *store;
}
@end
更改为全局变量,而不是实例变量。 C函数可以访问全局变量。但是,这确实意味着该类的每个实例共享相同的mData
,在这种情况下只有一个mData
而不是每个实例都有一个mData
。
因此,将实例变量设置为全局变量不是解决此类问题的一般解决方案,但是由于您不太可能拥有StoreTests
类的多个实例,因此它是一个合适的解决方案。情况下。
但是,您应该进行一项更改:您只能拥有一个带有程序的给定名称的全局变量,因此您的mData
必须是唯一的,并且可以通过中的任何代码访问程序,而不仅仅是StoreTests
的代码。你可以通过static
声明变量来缓解这个问题:
static int mData;
这会将变量保持为全局变量,但只会使声明与声明相同的文件中的代码可见,这可能只是StoreTests
的代码。
HTH
答案 1 :(得分:0)
我为我的问题找到了一个解决方案,即在mData
之上声明@interface StoreTests : XCTestCase
,如下所示:
int mData;
@interface StoreTests : XCTestCase {
Store *store;
}
@end
...