web-dev-qa-db-ja.com

Class Fooは、MyAppとMyAppTestCaseの両方に実装されています。 2つのうちの1つが使用されます。未定義のもの

最近、アプリケーションの単体テストを開始しました。このプロジェクト(Xcode4)は、単体テストバンドルなしで作成されたため、セットアップする必要がありました。ここから手順を実行しました: http://cocoawithlove.com/2009/12/sample-mac-application-with-complete.html そして、それは単純なクラスではうまく機能していましたが、今は他に依存しているクラスと別のクラスに依存しているクラスをテストするなど.

最初にリンカエラーが発生したため、テストケースターゲットに_*.m_ファイルを追加しましたが、テストしようとしているすべてのクラスに対して警告が表示されます。

Class Fooは、MyAppとMyAppTestCaseの両方に実装されています。 2つのうちの1つが使用されます。どちらが未定義です。

なぜだろうか?どうすれば解決できますか?単体テストのターゲットを設定するときに何かを見逃したのでしょうか?

編集-ソリューション

  • 「Bundle Loader」を$(BUILT_PRODUCTS_DIR)/AppName.app/AppNameに正しく設定します

  • 「デフォルトで非表示のシンボル」を[〜#〜] no [〜#〜]に設定します(ターゲットアプリケーションのビルド設定)。これは、デフォルトでYESであるため、リンカーエラーの原因です。私はこれに長い間苦労しています!.

ソース: XCode 4を使用した単体テストのリンクエラー?

63
nacho4d

Class Fooは、MyAppとMyAppTestCaseの両方に実装されています。 2つのうちの1つが使用されます。どちらが未定義です。

なぜだろうか?

両方の画像(アプリと単体テストバンドル)がクラスの実装を定義しているためです。クラスは、objcランタイムに動的にロードされます。 objcランタイムはフラットな名前空間を使用します。これの仕組み:

  • 依存関係から始まるバイナリがロードされます
  • 各バイナリがロードされると、objcクラスがobjcランタイムに登録されます
  • 特定の名前を持つクラスが2回ロードされる場合、動作は未定義です。クラスの1つの実装(同じ名前)をobjcランタイムにロードできます。

ここでのtypical問題は、1つの実装が返されることです-型が競合する場合(クラスが同じソースファイルから取得されない場合)、アプリがクラッシュする可能性があります。

通常、クラスの名前を変更するか、1つのイメージでクラスをエクスポートすることにより、これを回避します。クラスの名前の変更は明らかにあなたのケースには適用されません。 1つのファイルFoo.mがあります。このファイルは、2つのイメージが1つにあるはずなのに、コンパイル、エクスポート、およびロードされています。

これは、重複シンボルリンカーエラーとして解釈する必要があります。実装が同じソースファイル(および実装も同じ)であっても、これは修正する必要がある問題です。

どうすれば解決できますか?

Foo.mがアプリのクラスである場合、ユニットテストからFoo.mを削除する必要があります(コンパイルおよびリンクしないでください)。単体テストの一部である場合、コンパイルして単体テストターゲットにリンクしないでください。

その後、投稿の指示に従って、ユニットテストをアプリにリンク/ロードします。投稿のこの一般的な領域にあります:ここで、「WhereIsMyMac」は、単体テストを行うアプリケーションの名前です。これにより、テスト対象とアプリケーションがリンクされます(したがって、コンパイル時にリンカーエラーが発生しません)。重要な部分は、テストファイルが単体テストターゲット(のみ)でコンパイルされ、アプリケーションのクラスはコンパイルされ、アプリにリンクされます。それらを単に追加することはできません-それらは動的にリンクしてロードします。

単体テストのターゲットを設定するときに何かを見逃したのでしょうか?

リンクした記事から:

注:テスト対象は別の対象です。これは、ターゲットメンバーシップに注意する必要があることを意味します。すべてのアプリケーションソースファイルは、アプリケーションターゲットのみに追加する必要があります。テストコードファイルは、テスト対象にのみ追加する必要があります。

間違った部分は、おそらく単体テストバンドルのリンクフェーズとロードフェーズです。

43
justin

Cocoapodsを使用している場合、ポッドファイルには、テストターゲットではなく、メインターゲットのセクションの依存関係のみが必要です。テストターゲットに重複した依存関係を追加すると、OPのエラーメッセージが表示されます。

target 'MyProject' do
pod 'Parse'

end

target 'MyProjectTests' do

end

target 'MyProjectUITests' do

end
17
Richard

私にとっては、Fooクラスを単体テストターゲットのメンバーにするチェックボックスのチェックを外すだけでした。両方のターゲットのメンバーではなく、次のようになります。

Target Membership

画像が表示されない場合は、Xcodeの「ターゲットメンバーシップ」ペインのスクリーンショットです。 2つのターゲットがあります。1つは「A」アプリケーションアイコンとテスト名があります。もう1つは単体テストのターゲットであり、単体テストのアイコンがあります。

Target Membership
[X] Foo
[ ] FooTests
12
Steve HHH

NSZombiesを有効にしているので、デバイスとシミュレーターに展開したので、私にとってこれは起こりました。解決策は、シミュレーター構成に切り替えて[製品]-> [クリーン]を実行してから、デバイス構成に切り替えて同じことを行うことでした。エラーはなくなりました。これはビルドキャッシュに関連しています。

3
Geoff H

理由は、他のターゲットで定義されているApp Targetのビルド設定の_RUNPATH_SEARCH_PATHS_をオーバーライドするためです。

解決策:

App Targetに移動し、_RUNPATH_SEARCH_PATHS_ビルド設定を見つけ、そこに$(inherited)フラグを使用します:DebugおよびRelease

同じ問題に出くわします。私の状況では、クラスNSNotificationは/System/Library/Frameworks/Foundation.framework/Foundationの両方に実装されています。

0
suxinde2009