3

我的代码调用了一个 C 库函数:

@implementation Store
  ...
  -(void) doWork {
    // this is a C function from a library
    int data = getData(); 
    ...
  }
end

我正在对上述函数进行单元测试,我想getData()在我的测试中模拟 C 函数,这是我的测试用例:

@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()函数内部?

4

2 回答 2

1

您误解了实例方法和变量的工作方式。

每个实例方法都有一个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 函数可以访问全局变量。但是,这确实意味着该类的每个实例都共享相同的,在这种情况下只有一个,而不是每个实例一个。mDatamData

因此,将实例变量变为全局变量并不是解决此类问题的通用解决方案,但是由于您的类的实例不太可能拥有多个实例,StoreTests因此在这种情况下它是一个合适的解决方案。

但是,您应该进行一项更改:程序中只能有一个具有给定名称的全局变量,因此您的变量mData必须是唯一的,并且可以被程序中的任何代码访问,而不仅仅是StoreTests. 您可以通过将变量声明为static

static int mData;

这将变量保持为全局变量,但仅使其对与声明相同的文件中的代码可见,这可能只是StoreTests.

高温高压

于 2016-09-20T05:23:08.547 回答
0

我为我的问题找到了一种解决方案,即mData上面声明@interface StoreTests : XCTestCase,如下所示:

int mData;
@interface StoreTests : XCTestCase {
    Store *store;
}
@end
...
于 2016-09-20T03:48:45.137 回答