CocoaPodsをiOSロジックテストで使用するとライブラリが見つからない


148

私のpodspecのいくつかのライブラリーの機能を使用するプロジェクトのクラスに対して、いくつかのiOSロジックテストを記述しようとしています。Xcodeで提供される標準の単体テストバンドルを使用しています(ただし、アプリケーションテストではなく、単体テストのみ)。

たとえば、私はMagical Recordを使用していますが、そのライブラリは私のpodspecにリンクされています。それは私のワークスペースのポッドプロジェクトにあり、アプリがシミュレーターまたはデバイスで実行されているときに期待どおりに機能します。ただし、Magical Recordを使用するオブジェクトをテストにリンクしようとすると、Magical Recordからセレクターを見つけられないというリンカエラーが発生します。ロジックテストバンドルのHEADER_SEARCH_PATHを更新しようとしました。CocoaPodsによって作成されたヘッダーディレクトリにハードコーディングしても、うまくいきませんでした。

CocoaPodsライブラリを使用しないクラスに対してユニットテストを問題なく実行できます。

私はこれを間違っているのでしょうか?コンパイラにCocoaPodsライブラリを表示させるために、他に何かすべきですか?

回答:


224

CocoaPods 1.0では、このための構文が変更されました。これは次のようになります。

def shared_pods
    pod 'SSKeychain', '~> 0.1.4'
    ...
end

target 'Sail' do
    shared_pods
end

target 'Sail-iOS' do
    shared_pods
end

CocoaPods 1.0以前の回答

あなたが使いたいのはlink_withあなたのものPodfileです。何かのようなもの:

link_with 'MainTarget', 'MainTargetTests'

その後、pod install再度実行します。


7
これですぐに問題が解決しました。
mttrb 2013

9
これで奇妙なエラーが発生します-テストすると、isSubclassOfClass:呼び出しはNOどこに戻るかを返しYESます。これを説明できる唯一の理由は、依存関係がメインターゲットとテストターゲットの両方に実際にリンクされ、テストターゲットのバンドルローダーがメインバンドルをロードするときに、どのクラスを取るかを決定できないためです。
2013

4
isKindOfClass:復帰NOすべきときに復帰するのと同じ問題がありYESます。Classテストしているオブジェクトのへのポインターと、Class比較したいクラスののポインターを記録すると、2つの異なる値になります。明らかに、App Bundleのコードは、ユニットテストのコードとは異なるシンボルをクラスに使用しています。誰かがこれを解決する方法を見つけましたか?
ニコラスハート

2
他の人が述べているエラーのため、これは良い方法ではないと思います。ビットに基づいて構成ファイルを更新することに固執します。libPods.aを2回リンクしていないことを確認してください。
Bob Spryn 2014年

3
これは、複数のターゲットでポッドを設定する公式のCocoaPodsの方法であるため、受け入れられた答えになるはずです。たくさんキース!
cschuff 2014

174

私は、アプリのメインターゲットがCocoaPodsライブラリから設定を受信する方法を見て、これを理解しました。CocoaPodsには、Pods.xcconfigという名前の.xcconfigファイルが含まれています。このファイルには、すべてのヘッダー検索パスが含まれています。

プロジェクトナビゲーターでプロジェクトを見て、[情報]タブをクリックすると、上部のセクションにビルド構成が一覧表示されます。さまざまな構成の開閉用三角ボタンを開くと、メインターゲットの下にポッドが一覧表示されます。ドロップダウンをクリックして、ポッドをロジックテストターゲットにも追加する必要がありました。

構成のスナップショット

私はまたの設定をコピーしなければならなかった$(inherited)${PODS_HEADERS_SEARCH_PATHS}HEADER_SEARCH_PATHS /私のメインターゲットからとビルド設定の下にロジックテストターゲットにそれらをコピー。

最後に、ロジックテストターゲットのリンクバイナリとライブラリのビルドフェーズにlibPods.aを追加する必要がありました。

これが他の誰かを助けることができることを願っています。


鮮やかさ!私はユニットテストにMagicalRecordとOCMockitoとOCHamcrestを使用しています。この修正により、CocoaPodsからすべてをインストールできるようになりました。ありがとう!
フォグマイスター2013年

4
これでうまくいきました、ありがとう。注:libPods.aをテストプロジェクトとメインプロジェクトの両方に追加する必要はありませんでした。これにより、重複シンボルエラーが発生します
Craig Bruce

私にとっては、「ユーザー定義」のビルド設定もコピーする必要がありました。ヘッダー検索パスは、テストターゲットで定義されていない$ PODS_ROOTを参照しています。エディター->ビルド設定の追加->ユーザー定義設定の追加の順に進み、メインのターゲットから$ PODS_ROOT値をコピーすることで追加できます。
死神

11
これはこれを修正する正しい方法ではありません。link_withで回答をご覧ください。ポッドファイルでターゲットごとに異なるポッドを指定することもできます。つまり、テストターゲットにOCMockitoのみを含めます。
dbainbridge 2014年

はいはいはい!この回答の前に、プロジェクトからTestターゲットを削除する必要がありました。おかげで男:)
ジョシップB.

53

ここで私が見つけた解決策がありますCocoaPodsを使用した単体テスト

Xcodeでプロジェクトファイルを開き、プロジェクト(ターゲットではない)を選択します。右側のパネルに、構成と呼ばれるセクションがあります。テストターゲットの[構成ファイルに基づく]列でポッドを選択します。

ここに画像の説明を入力してください


さて、Spectaメインプロジェクトではなくテストプロジェクトとリンクしたいなど、テスト固有の依存関係がある場合はどうでしょうか。:S
fatuhoku 2015年

これは機能し、ポッドの構成や設定を変更する必要はありません...優れたソリューション。
Richard

1
このソリューションではエラーが発生する可能性がありますが、Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined. これはCocoapodsのバグが原因であるようです。以下の@JRV回答を参照してください。
Richard

これらは単なる警告ではありません。このような設定では、適切なXcodeコードカバレッジデータが生成されず、ほとんどの場合、起動時に単体テストがハングします。
i4niac 2016年

Estimote SDKをドラッグアンドドロップで手動でインポートしましたが、ポッドが取得されません。これを解決するには?
Guru Teja

18

ライブラリをテストターゲットにリンクする必要があるという他の回答にも同意します。しかし、これまでのところ、どの提案も私を助けませんでした。@fabbがコメントに書いているように、「テストすると、isSubclassOfClass:呼び出しはYESを返す必要がある場所でNOを返します。これを説明できる唯一の理由は、依存関係がメインターゲットとテストターゲットの両方に実際にリンクされ、テストターゲットのバンドルがリンクされるときです。ローダーはメインバンドルをロードします。どのクラスを取るかを決定できません。」このスレッドの以前のすべての提案で同じ問題が発生します。

私が作業しなければならない解決策は、メインターゲットとテストターゲットに特定のポッドを定義するようにPodfileを更新することでした。

target 'MyTarget' do
   pod 'AFNetworking', '~> 2.5.0'
   pod 'Mantle', '~> 1.5'
end

target 'MyTargetTests' do
   pod 'OCMockito', '~> 1.3.1'
end

だった必要な私は、テストの特定のポッドを使用していなかったにもかかわらず、私のテスト対象のためのポッドを指定します。そうしないと、CocoaPodsが必要なリンクロジックをプロジェクトに挿入しません。

このリンクは私がこの結論に到達するのを助けたものです。


1
CocoaPodsの問題へのリンクをありがとう-それは私の問題を解決するのに役立ちました!
karlbecker_com、2015年

はい!!!!この問題は私を悩ませてきました。これは私が出会った唯一の賢明なココアポッドの答えです。
DonnaLea 2015年

1.xでこれを処理するより良い方法があります:stackoverflow.com/a/40866889/2799670
Darren Black

6

:exclusive => trueアプリケーションテストターゲットでのシンボルの重複エラーを回避するために追加しました。

target 'myProjectTests', :exclusive => true do
   pod 'OCMock', :head
   pod 'XCTAsyncTestCase', :git => 'https://github.com/iheartradio/xctest-additions.git'
end

link_with 'myProject', 'myProjectTests'

アプリケーションテストのターゲットをロジックユニットテストのターゲットに変更すると、リンカーエラーが発生します。を削除した後:exclusive => true、すべてが再び機能します。

target 'myProjectTests', do
   pod 'OCMock', :head
   pod 'XCTAsyncTestCase', :git => 'https://github.com/iheartradio/xctest-additions.git'
end

link_with 'myProject', 'myProjectTests'

:exclusive => trueは、外部のすべてをdo...endにリンクするべきではないと述べていますmyProjectTests。これは、アプリケーションテストターゲットでは妥当ですが、ロジックテストターゲットでリンカーエラーが発生します。


この質問に対するJRVの回答のおかげで発見されたこのCocoaPodsの問題に関するkylefの回答に示されているように、排他的な解決策が私にとっての解決策でした!
karlbecker_com、2015年

1
はい、@ karlbecker_comによってリンクされたgithubでこの問題を読む必要があります。これは、ココアポッドの長期的な制限にすぎないようです。そこでの議論によると、link_withは必要ありません。テストターゲットを追加して、:exclusiveを使用します。テストターゲットに特定のポッドが必要ない場合は、とにかく1つ追加してください。そうしないと、cocoapodがそれを処理しません。
kball 2015年

@kball link_withを必要としないものはどれですか?アプリケーションテストまたはロジックユニットテスト?
Hai Feng Kao

それを使用する別の理由がない限り、link_withはまったく必要ありません。そして一般的に言えば、それらのポッドをテストバンドルにリンクしたくありません。それらは、アプリバンドルで1回だけリンクされ、依存関係を通じてテストによって参照される必要があります(デフォルトで非表示のシンボルがオフであることを確認します)。それ以外の場合、2つのバージョンのポッドが存在するため、動作は未定義です。1つはアプリターゲットに含まれ、もう1つはテストターゲットに含まれます。
kball 2015年

6

@Keith Smileyソリューションに従ってlink_withを使用できます。

共通のポッドと各ターゲットの詳細がある場合は、「def」オプションを使用してポッドのグループを定義できます。後で「def」を排他的ターゲットで使用します。

def import_pods
    pod 'SSKeychain'
end

target 'MyProjectTests', :exclusive => true do
  import_pods
end

target 'MyProject', :exclusive => true do
  import_pods
  pod 'Typhoon'
end

上記の例では、両方のターゲットに「SSKeychain」を追加し、「MyProject」ターゲットにのみ「Typhoon」を追加しました


5

この問題の私の解決策は、Podfileを変更して、このように両方のターゲットにライブラリを含めることでした。

target "MyApp" do  
    pod 'GRMustache', '~> 7.0.2'
end

target "MyAppTests" do
    pod 'GRMustache', '~> 7.0.2'
end

また、Swiftを使用しているため、MyApp-Bridging-Header.hファイルを含めるようにテストターゲットも構成する必要がありました。([ビルド設定]タブの[Swiftコンパイラ]グループ)


3
注意—ポッドを追加し続けると、ビルド時間が大幅に増加します。
fatuhoku

@fatuhokuはそれを知りませんでした。ビルド時間が長くなる理由を教えてください。
Qw4z1 2015年

2
さて、ポッドの各言及はPodsプロジェクトのターゲットです。ポッドに2回言及することで(テスト用に1回、アプリ用に1回)、2つのターゲットセットが作成されます。これにより、設定作業pod installが事実上2倍になります。ポッドが15個を超えるまでは問題になりませんが、それまではあまり心配しないでください。
fatuhoku 2015年

1
これは、Cocoapods 1.0で動作する唯一のソリューションです
William Entriken

1.x以降、これはアプリの依存関係を継承するテストの公式メソッドです。stackoverflow.com
Darren Black

4

いくつかのバージョン管理中にいくつかのライブラリファイルを失ったときにも、同様のことが起こりました。ポッドで引き続きライブラリファイルを確認しましたが、実際のコードが見つからないため、XCodeはそれがなくなったと言いました。残念なことに、「ポッドインストール」を実行しても、失われたファイルがすぐに復元されるわけではありませんでした。

次のようにして、ポッドを手動で取り外して交換する必要がありました。

  1. Podfileからライブラリを削除する
  2. ライブラリを完全に削除するには、「ポッドインストール」を実行します
  3. ライブラリをPodfileに戻す
  4. 「ポッドインストール」を再度実行します

これにより、問題のライブラリが元の形式に戻ります。


2

またlibPods.a、2回追加した場合、次のような厄介なエラーが発生することにも注意してください。

232 duplicate symbols for architecture i386

これを修正するにlibPods.aは、プロジェクトエクスプローラーで参照の1つを削除するだけです。


2

CocoaPods 1.x以降、ターゲットと対応するテストターゲット間の共有依存関係を宣言する新しい方法があります。私は今までMark Struzinskiが承認したソリューションを使用していましたが、この方法を使用すると、テストを実行するときに次のような大量の警告が表示されました。

Class SomeClass is implemented in both /Path/To/Test/Target and /Path/To/App/Target. One of the two will be used. Which one is undefined.

CocoaPods 1.xでは、次のように、-Testターゲットを親ターゲットの検索パスを介して継承するものとして宣言できます。

target 'MyApp' do
    pod 'aPod'
    pod 'anotherPod'
    project 'MyApp.xcodeproj'
end
target 'MyAppTests' do
    inherit! :search_paths
    project 'MyApp.xcodeproj'
end

これにより、複数のバイナリコピーなしで、-Testターゲットがアプリターゲットの依存関係にアクセスできるようになります。これにより、テストのビルド時間が大幅に短縮されました。


2

これを試してみてください

構成でポッドを設定する必要があります、

Xcodeプロジェクト(プロジェクト)のProject-> Info-> Configurationsは、Debug、Release(および他に何があるか)のメインプロジェクト 'Pods'に設定する必要があります。「ヘッダーが見つかりません–検索パスが含まれていません」を参照してください

ここに画像の説明を入力してください

これが誰かに役立つことを願っています。


1

私はiOSでGoogleMaps Objective-C PODをSwiftアプリと統合しているので、私にとって問題は、ビルド設定のテストターゲットにブリッジヘッダーファイル(SWIFT_OBJC_BRIDGING_HEADER)への参照がないことでした。アプリとテストアプリの両方のターゲットがそれを指していることを確認して、サードパーティのAPI呼び出し(マップAPIなど)を迅速な単体テストで使用できるようにします。


1
私はあなたと同じような設定をしています。既にテストターゲットにブリッジヘッダーを追加していますが、「No such module 'GoogleMaps'」というエラーが表示されimport GoogleMapsます。
Nicolas Miari、2016

0

次の構文は私にとって最良の結果をもたらします(cocoapod v.1.2.1でテスト済み):

https://github.com/CocoaPods/CocoaPods/issues/4626#issuecomment-210402349

 target 'App' do
    pod 'GoogleAnalytics' , '~> 3.0'
    pod 'GoogleTagManager' , '~> 3.0'

     pod 'SDWebImage', '~>3.7'
     platform :ios, '8.0'
     use_frameworks!

     target 'App Unit Tests' do
         inherit! :search_paths
     end
 end

これがないと、シンボルの重複に関するテスト実行中に警告が表示されます。

この警告が消えた後。


0

XCTestでOpenCVを使用するときに問題が発生しました。それは私にのUndefined symbols for architecture arm64ようなクラスのリンカーエラーを与えていましたcv::Mat。私はpod 'OpenCV', '~> 2.0'メインターゲットの下でを使用してCocoaPodsを介してOpenCVをインストールしています。OpenCVの依存関係をテストターゲットの下に置いたり、inherit! :search_pathsどれを使用したりしても、どれもうまくいきませんでした。解決策はそのabstract_targetようなものを作成することでした:

# Uncomment the next line to define a global platform for your project
platform :ios, '6.1.6'

abstract_target 'Shows' do
  pod 'RMVision', path: '../..'
  pod 'RMShared', path: '../../../RMShared'
  pod 'OpenCV', '~> 2.0'

  target 'RMVisionSample' do
    # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
    # use_frameworks!

    # Pods for RMVisionSample
  end

  target 'RMVisionSampleTests' do
    # inherit! :search_paths
    # Pods for testing
  end

  target 'RMVisionBenchmarks' do
    # inherit! :search_paths
    # Pods for testing
  end

end 

また、プロジェクトをクリーンアップし、テスト時に最初からやり直すのに役立つpod deintegratepod cleanコマンドも役立ちます。これら2つはを使用してインストールでき[sudo] gem install cocoapods-deintegrate cocoapods-cleanます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.