Perpustakaan tidak ditemukan saat menggunakan CocoaPods dengan tes logika iOS

148

Saya mencoba menulis beberapa tes logika iOS terhadap kelas di proyek saya yang menggunakan fungsionalitas dari beberapa perpustakaan di podspec saya. Saya menggunakan bundel tes unit standar yang disediakan dalam Xcode (meskipun bukan Tes Aplikasi, hanya Tes Unit).

Sebagai contoh, saya menggunakan Magical Record, dan saya memiliki perpustakaan yang terhubung di podspec saya. Itu ada di proyek Pods di ruang kerja saya, dan berfungsi seperti yang diharapkan ketika aplikasi berjalan di simulator atau di perangkat. Ketika saya mencoba untuk menautkan ke objek pengujian yang menggunakan Magical Record, saya mendapatkan kesalahan linker yang menyatakan bahwa ia tidak dapat menemukan penyeleksi dari Magical Record. Saya telah mencoba memperbarui HEADER_SEARCH_PATH saya di bundel pengujian logika saya, bahkan sulit mengkodekannya ke direktori header yang dibuat oleh CocoaPods, tetapi tidak berhasil.

Saya bisa menjalankan tes unit terhadap kelas yang tidak menggunakan pustaka CocoaPods tanpa masalah.

Apakah saya salah tentang ini? Haruskah saya melakukan sesuatu yang lain untuk membuat kompiler melihat pustaka CocoaPods?

Mark Struzinski
sumber

Jawaban:

224

CocoaPods 1.0 telah mengubah sintaks untuk ini. Sekarang terlihat seperti ini:

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

target 'Sail' do
    shared_pods
end

target 'Sail-iOS' do
    shared_pods
end

Pra CocoaPods 1.0 menjawab

Apa yang ingin Anda gunakan adalah link_withdari Anda Podfile. Sesuatu seperti:

link_with 'MainTarget', 'MainTargetTests'

Kemudian jalankan pod installlagi.

Keith Smiley
sumber
7
Ini segera memperbaiki masalah bagi saya.
mttrb
9
Saya mendapatkan kesalahan aneh dengan ini - saat pengujian, isSubclassOfClass:panggilan kembali ke NOtempat mereka seharusnya kembali YES. Satu-satunya alasan saya bisa menjelaskan ini adalah bahwa dependensi benar-benar terhubung dengan target utama dan target pengujian, dan ketika bundel loader target uji memuat bundel utama, ia tidak dapat memutuskan kelas mana yang akan diambil.
Fabb
4
Saya memiliki masalah yang sama dengan isKindOfClass:pengembalian NOketika harus kembali YES. Jika saya mencatat pointer ke Classobjek saya, saya menguji dan Classkelas yang ingin saya bandingkan dengan mereka adalah dua nilai yang berbeda. Jelas kode saya dari bundel aplikasi menggunakan simbol yang berbeda untuk kelas daripada kode dari unit test saya. Adakah yang menemukan cara untuk menyelesaikan ini?
Nicholas Hart
2
Saya tidak berpikir ini adalah cara yang baik untuk pergi karena kesalahan beberapa orang lain telah disebutkan. Tetap dengan memperbarui file konfigurasi 'berdasarkan' bit. Pastikan Anda belum menautkan libPods.a dua kali.
Bob Spryn
3
Ini harus menjadi jawaban yang diterima karena ini adalah cara CocoaPods resmi untuk menyiapkan Pod dengan banyak target. Terima kasih banyak Keith!
cschuff
174

Saya menemukan yang ini dengan melihat bagaimana target utama aplikasi saya menerima pengaturan dari perpustakaan CocoaPods. CocoaPods menyertakan file .xcconfig bernama Pods.xcconfig. File ini berisi semua jalur pencarian tajuk.

Jika Anda melihat proyek Anda di navigator proyek dan mengklik tab Info, Anda akan melihat konfigurasi bangunan Anda tercantum di bagian atas. Jika Anda membuka segitiga pengungkapan untuk berbagai konfigurasi Anda, Anda akan melihat Pods tercantum di bawah target utama Anda. Saya harus mengklik drop down dan menambahkan Pods ke target tes logika juga.

Konfigurasi Snapshot

Saya juga harus menyalin pengaturan $(inherited)dan ${PODS_HEADERS_SEARCH_PATHS}dari target utama saya dan menyalinnya ke target tes logika di bawah Build Settings / HEADER_SEARCH_PATHS.

Akhirnya, saya harus menambahkan libPods.a dalam fase membangun Link Binary with Libraries untuk target tes logika saya.

Semoga ini bisa membantu orang lain.

Mark Struzinski
sumber
Cemerlang! Saya menggunakan MagicalRecord dan juga OCMockito dan OCHamcrest untuk pengujian unit. Dengan perbaikan ini sekarang saya dapat menginstal semuanya melalui CocoaPods! Terima kasih!
Fogmeister
4
Ini berhasil untuk saya, terima kasih. CATATAN .. Saya tidak perlu menambahkan libPods.a ke dalam proj tes dan proj utama. Ini menyebabkan kesalahan simbol duplikat
Craig Bruce
Bagi saya, saya juga harus menyalin pengaturan build "Buatan Pengguna". Jalur Pencarian Header merujuk ke $ PODS_ROOT yang tidak ditentukan pada target pengujian. Anda dapat menambahkannya dengan masuk ke Editor-> Tambah Pengaturan Build-> Tambahkan Pengaturan Buatan Pengguna kemudian menyalin nilai $ PODS_ROOT dari target utama.
Shinigami
11
Ini bukan cara yang benar untuk memperbaikinya. Lihat jawaban dengan tautan_dengan. Anda juga dapat menentukan berbagai pod berdasarkan basis target dalam file pod Anda, yaitu, hanya menyertakan OCMockito dalam target pengujian Anda.
dbainbridge
Ya ya ya! Sebelum jawaban ini saya harus menghapus target Uji dari proyek saya! Terima kasih kawan :)
Josip B.
53

Ada solusi yang saya temukan di sini Unit Test Dengan CocoaPods :

Buka file proyek dalam Xcode, lalu pilih Project (bukan target), di panel kanan, ada bagian yang disebut Konfigurasi. Pilih Pods di kolom "Based on Configuration file" untuk target pengujian Anda.

masukkan deskripsi gambar di sini

Mingming
sumber
Nah, bagaimana jika ada dependensi khusus tes, seperti Spectaitu Anda ingin menghubungkan dengan proyek pengujian tetapi tidak dengan proyek utama? : S
fatuhoku
Ini berfungsi dan tidak memerlukan perubahan apa pun pada konfigurasi atau penyiapan pod ... Solusi luar biasa.
Richard
1
Meskipun solusi ini dapat membuat kesalahan: Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined. Ini tampaknya disebabkan oleh bug di Cocoapods; lihat jawaban @JRV di bawah ini.
Richard
Itu bukan sekadar peringatan. Dengan pengaturan seperti itu tidak ada data cakupan kode Xcode yang tepat dihasilkan dan unit test hanya hang selama peluncuran dalam banyak kasus
i4niac
Saya telah mengimpor Estimote SDK secara manual dengan drag and drop, saya tidak mendapatkan pod. Bagaimana cara mengatasinya?
Guru Teja
18

Saya setuju dengan jawaban lain yang mengatakan bahwa perpustakaan perlu dikaitkan dengan target tes. Namun sejauh ini tidak ada saran yang membantu saya. Seperti @fabb menulis dalam komentar: "saat pengujian, isSubclassOfClass:panggilan kembali TIDAK di mana mereka harus kembali YA. Satu-satunya alasan saya dapat menjelaskan ini adalah bahwa dependensi benar-benar terhubung dengan target utama dan target pengujian, dan ketika bundel target uji loader memuat bundel utama, tidak dapat memutuskan kelas mana yang akan diambil. " Saya mendapatkan masalah yang sama dengan semua saran sebelumnya di utas ini.

Solusi yang saya dapat kerjakan adalah memperbarui Podfile saya untuk menentukan Pods spesifik untuk target utama dan target pengujian saya:

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

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

Itu perlu untuk menentukan Pod untuk target pengujian saya meskipun saya tidak menggunakan Pods spesifik pengujian. Kalau tidak, CocoaPods tidak akan memasukkan logika tautan yang diperlukan dalam proyek saya.

Tautan ini yang membantu saya sampai pada kesimpulan ini.

JRV
sumber
1
Terima kasih atas tautan ke masalah CocoaPods - yang membantu saya memecahkan masalah saya!
karlbecker_com
IYA!!!! Masalah ini telah mengganggu saya. Ini adalah satu-satunya jawaban cocoapod masuk akal yang saya temui.
DonnaLea
Ada cara yang lebih baik untuk menangani hal ini di bawah 1.x: stackoverflow.com/a/40866889/2799670
Darren Black
6

Saya menambahkan :exclusive => trueuntuk menghindari kesalahan simbol duplikat dalam target pengujian aplikasi.

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

link_with 'myProject', 'myProjectTests'

Ketika saya mengubah target tes aplikasi ke unit tes logika satu, kesalahan linker terjadi. Setelah saya hapus :exclusive => true, semuanya berfungsi lagi.

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

link_with 'myProject', 'myProjectTests'

:exclusive => truemenyatakan bahwa segala sesuatu di luar do...endTIDAK boleh ditautkan myProjectTests, yang masuk akal dalam target pengujian aplikasi, tetapi akan menyebabkan kesalahan linker dalam target pengujian logika.

Hai Feng Kao
sumber
Eksklusif adalah solusi bagi saya, seperti yang ditunjukkan dalam jawaban kylef pada masalah CocoaPods ini , yang ditemukan berkat jawaban JRV pada pertanyaan ini!
karlbecker_com
1
Ya, semua orang harus membaca masalah itu di github yang ditautkan oleh @karlbecker_com. Tampaknya ini hanyalah keterbatasan jangka panjang dari cocoapods. Menurut diskusi di sana, link_with tidak diperlukan. Cukup tambahkan target tes dan gunakan: eksklusif. Jika target pengujian Anda tidak membutuhkan pod tertentu, tambahkan saja jika tidak, cocoapod tidak akan memprosesnya.
kball
@kball Yang mana yang tidak perlu link_with? Tes aplikasi atau tes unit logika?
Hai Feng Kao
Kecuali Anda memiliki alasan lain untuk menggunakannya, Anda seharusnya tidak perlu link_with sama sekali. Dan secara umum Anda tidak ingin menautkan pod tersebut dengan bundel pengujian Anda. Mereka hanya boleh dihubungkan satu kali, dalam bundel aplikasi, dan kemudian direferensikan oleh pengujian Anda melalui dependensi (memastikan Simbol Tersembunyi secara Default tidak aktif). Jika tidak, perilaku tidak akan ditentukan karena dua versi pod akan ada - satu termasuk dalam target aplikasi, satu di target pengujian.
kball
6

Anda dapat menggunakan link_with sesuai dengan solusi @Keith Smiley.

Jika Anda memiliki pod umum, dan spesifik untuk setiap target, Anda mungkin ingin menggunakan opsi "def" untuk menentukan grup pod. dan gunakan "def" nanti dalam target eksklusif.

def import_pods
    pod 'SSKeychain'
end

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

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

dalam contoh di atas, saya menambahkan 'SSKeychain' ke kedua target, dan 'Typhoon' hanya untuk target 'MyProject'

Elihay
sumber
5

Solusi saya untuk masalah ini adalah mengubah Podfile saya untuk memasukkan perpustakaan di kedua target seperti ini

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

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

Dan karena saya menggunakan swift saya juga harus mengkonfigurasi target pengujian untuk memasukkan MyApp-Bridging-Header.hfile. (Di grup Swift Compiler di bawah tab Build Settings)

Qw4z1
sumber
3
Hati-hati - ini akan meningkatkan waktu pembuatan Anda dengan banyak, karena Anda terus menambahkan lebih banyak polong!
fatuhoku
@fatuhoku tidak tahu itu. Bisakah Anda memberikan beberapa wawasan mengapa itu meningkatkan waktu pembuatan?
Qw4z1
2
Nah, setiap penyebutan pod adalah target dalam Podsproyek Anda . Dengan menyebutkan pod Anda dua kali (satu kali untuk pengujian dan satu lagi untuk aplikasi), Anda akan memiliki dua set target. Ini secara efektif menggandakan pekerjaan konfigurasi yang pod installharus dilakukan. Ini tidak akan menjadi masalah sampai Anda memiliki> 15 pod, jadi jangan terlalu khawatir sampai saat itu.
fatuhoku
1
Ini adalah satu-satunya solusi yang bekerja untuk saya dengan Cocoapods 1.0
William Entriken
Mulai dari 1.x, ini adalah metode resmi untuk pengujian yang mewarisi dependensi aplikasi: stackoverflow.com/a/40866889/2799670
Darren Black
4

Saya memiliki kejadian serupa ketika saya kehilangan beberapa file perpustakaan selama beberapa kontrol versi. Saya masih melihat file perpustakaan di Pods saya tetapi dengan kode yang sebenarnya hilang, XCode mengatakan itu hilang. Yang membuatku cemas, menjalankan 'pod install' tidak segera mengembalikan file yang hilang.

Saya harus menghapus dan mengganti pod secara manual dengan melakukan hal berikut:

  1. Hapus perpustakaan dari Podfile
  2. Jalankan 'pod install' untuk menghapus perpustakaan sepenuhnya
  3. Kembalikan perpustakaan ke dalam Podfile
  4. Jalankan 'pod install' lagi

Ini akan mengembalikan perpustakaan ke bentuk aslinya.

Maxwell
sumber
2

Perlu juga dicatat bahwa jika Anda telah libPods.amenambahkan dua kali, Anda akan mendapatkan beberapa kesalahan buruk seperti ini:

232 duplicate symbols for architecture i386

Untuk memperbaikinya, hapus saja salah satu libPods.areferensi di Project Explorer Anda.

Mat Ryer
sumber
2

Pada CocoaPods 1.x, ada cara baru untuk mendeklarasikan dependensi bersama antara target dan target tes yang sesuai. Saya telah menggunakan solusi yang diterima oleh Mark Struzinski sampai saat ini, tetapi menggunakan metode ini menghasilkan sejumlah besar peringatan ketika menjalankan tes saya bahwa:

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.

Dengan CocoaPods 1.x kita dapat mendeklarasikan target -Test sebagai warisan melalui jalur pencarian target induk, seperti:

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

Ini akan menghasilkan target -Tes memiliki akses ke dependensi target aplikasi, tanpa banyak salinan biner. Ini secara serius mempercepat waktu pengujian bagi saya.

Darren Black
sumber
2

Coba ini berfungsi untuk saya,

Kita perlu mengatur Pods di Configurations,

Project-> Info-> Konfigurasi dalam proyek Xcode (proyek Anda) harus diatur ke proyek utama 'Pods' untuk Debug, Release (dan apa pun yang Anda miliki). Lihat "Header tidak ditemukan - jalur pencarian tidak termasuk"

masukkan deskripsi gambar di sini

Semoga ini bisa membantu seseorang.

Jaywant Khedkar
sumber
1

Saya bekerja dengan integrasi POD GoogleMaps Objective-C di iOS dengan aplikasi Swift saya dan bagi saya masalahnya adalah bahwa target Pengujian tidak memiliki referensi ke File Header Bridge ( SWIFT_OBJC_BRIDGING_HEADER ) di Pengaturan Bangun. Pastikan aplikasi Anda dan target aplikasi pengujian menunjukkan hal itu sehingga panggilan API pihak ketiga (Maps API, dll.) Dapat digunakan dalam pengujian unit cepat.

appledevguru
sumber
1
Saya memiliki pengaturan yang sama seperti Anda. Saya telah menambahkan header penghubung ke target pengujian, Namun saya mendapatkan kesalahan "Tidak ada modul 'GoogleMaps'" di import GoogleMaps.
Nicolas Miari
0

Sintaks selanjutnya memberikan hasil terbaik bagi saya (diuji dengan 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

Tanpa ini saya memiliki peringatan saat uji coba tentang simbol duplikat.

Setelah peringatan ini hilang.

Maxim Kholyavkin
sumber
0

Saya punya masalah menggunakan OpenCV di bawah XCTest. Itu memberi saya kesalahan linker Undefined symbols for architecture arm64untuk kelas suka cv::Mat. Saya menginstal OpenCV melalui CocoaPods menggunakan di pod 'OpenCV', '~> 2.0'bawah target utama. Tidak peduli sekeras apa pun saya mencoba untuk meletakkan ketergantungan OpenCV di bawah target pengujian atau inherit! :search_pathstidak menggunakannya . Solusinya adalah membuat abstract_targetseperti:

# 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 

Juga berguna adalah pod deintegrate& pod cleanperintah yang membantu untuk membersihkan proyek dan memastikan bahwa Anda mulai baru saat pengujian. Anda dapat menginstal keduanya menggunakan [sudo] gem install cocoapods-deintegrate cocoapods-clean.

Foti Dim
sumber