3

私のコードは、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()関数?

4

2 に答える 2

1

インスタンス メソッドと変数がどのように機能するかを誤解しています。

すべてのインスタンス メソッドにはself、現在のインスタンス (または「現在のオブジェクト」) を参照する変数があり、 などのインスタンス変数の使用は、 を使用してmDataその変数にアクセスするための省略形です。アクセス。したがって、「ロングハンド」で書かれた方法は次のとおりです。selfself->mData->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 関数はグローバル変数にアクセスできます。ただし、これは、クラスのすべてのインスタンスが同じ を共有することを意味します。この場合、インスタンスごとに 1 つではなく、1 つだけです。mDatamData

したがって、インスタンス変数をグローバルにすることは、このような問題に対する一般的な解決策ではありませんが、クラスのインスタンスが複数ある可能性は低いためStoreTests、この場合の適切な解決策です。

ただし、1 つの変更を行う必要があります。プログラムで指定された名前を持つグローバル変数は 1 つしか持てないため、mData一意である必要があり、のコードだけでなく、プログラム内の任意のコードからアクセスできますStoreTestsstatic変数を次のように宣言することで、これを軽減できます。

static int mData;

これにより、変数はグローバルとして保持されますが、宣言と同じファイル内のコードにのみ表示されます。これはおそらくStoreTests.

HTH

于 2016-09-20T05:23:08.547 に答える
0

私は自分の質問に対する1つの解決策を見つけました.declare mDataabove@interface StoreTests : XCTestCaseは、次のようなものです:

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