在我的情况下使用未声明的标识符错误

时间:2016-09-20 03:12:12

标签: ios objective-c unit-testing xctest xctestcase

我的代码调用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()函数吗?

2 个答案:

答案 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
...