İOS mantık testleriyle CocoaPod'lar kullanılırken kütüphaneler bulunamadı


148

Projemde, podspec'imdeki bazı kitaplıklardan işlevsellik kullanan sınıflara karşı bazı iOS mantık testleri yazmaya çalışıyorum. Xcode'da sağlanan standart birim test paketini kullanıyorum (Uygulama Testleri olmasa da, sadece Birim Testleri).

Örneğin, Magical Record kullanıyorum ve podspec'imde bu kütüphaneyi bağlıyorum. Çalışma alanımdaki Pods projesinde mevcut ve uygulama simülatörde veya cihazda çalışırken beklendiği gibi çalışıyor. Ancak, Magical Record kullanan nesneyi test etmeye çalıştığımda, Magical Record'tan seçicileri bulamadığını belirten bir linker hatası alıyorum. Mantık testi paketimde HEADER_SEARCH_PATH'ımı güncellemeyi denedim, hatta CocoaPods tarafından oluşturulan üstbilgiler dizinine kodlama yaptım, ama şans yok.

Sorunsuz bir şekilde CocoaPods kütüphaneleri kullanmayan sınıflara karşı birim testleri çalıştırabilirim.

Buna yanlış mı gidiyorum? Derleyicinin CocoaPods kütüphanelerini görmesini sağlamak için başka bir şey yapmalı mıyım?

Yanıtlar:


224

CocoaPods 1.0 bunun sözdizimini değiştirdi. Şimdi şöyle görünüyor:

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

target 'Sail' do
    shared_pods
end

target 'Sail-iOS' do
    shared_pods
end

CocoaPods öncesi 1.0 cevap

Kullanmak istediğiniz şey link_withsizin Podfile. Gibi bir şey:

link_with 'MainTarget', 'MainTargetTests'

Sonra pod installtekrar çalıştırın .


7
Bu benim için derhal sorunu çözdü.
mttrb

9
Bununla garip hatalar alıyorum - test ederken, isSubclassOfClass:çağrılar geri dönmeleri NOgereken yere geri dönüyor YES. Bunu açıklayabilmemin tek nedeni, bağımlılıkların hem ana hem de test hedefiyle gerçekten bağlantılı olması ve test hedefinin paket yükleyicisi ana paketi yüklediğinde, hangi sınıfı alacağına karar veremez.
fabb

4
Ne zaman dönmelidir isKindOfClass:dönen ile aynı sorunu var . İşaretçiyi test ettiğim nesnenin günlüğüne kaydedersem ve karşılaştırmak istediğim sınıfın iki farklı değeri vardır. Açıkçası, uygulama paketindeki kodum, sınıf için birim testlerimdeki koddan farklı bir sembol kullanıyor. Herkes bunu çözmek için bir yol buldu mu? NOYESClassClass
Nicholas Hart

2
Bazılarının bahsettiği hatalar nedeniyle bunun iyi bir yol olduğunu düşünmüyorum. Yapılandırma dosyasını 'dayalı' bit güncellemeye devam edin. LibPods.a dosyasını iki kez bağlamadığınızdan emin olun.
Bob Spryn

3
Bu, kabul edilen cevap olmalıdır, çünkü bu, birden fazla hedefi olan Pod'ları kurmanın resmi CocoaPods yoludur. Çok teşekkürler Keith!
cschuff

174

Uygulamamın ana hedefinin CocoaPods kütüphanesinden ayarları nasıl aldığını inceleyerek bunu anladım. CocoaPods, Pods.xcconfig adlı bir .xcconfig dosyası içerir. Bu dosya tüm başlık arama yollarını içerir.

Projenize proje gezgininde bakar ve Bilgi sekmesine tıklarsanız, yapı yapılandırmalarınızın üst bölümde listelendiğini göreceksiniz. Farklı yapılandırmalarınız için açıklama üçgenini açarsanız, ana hedefinizin altında Pod'ların listelendiğini görürsünüz. Açılır kutuyu tıklatmam ve mantık testi hedefine Pod'lar eklemem gerekiyordu.

Konfigürasyon Anlık Görüntüsü

Ayrıca, ana hedefimin ayarlarını $(inherited)ve ${PODS_HEADERS_SEARCH_PATHS}ana hedefimden kopyalayıp Oluşturma Ayarları / HEADER_SEARCH_PATHS altındaki mantık testi hedefine kopyalamam gerekiyordu.

Son olarak, mantık testleri hedefim için Bağlantı İkili Kütüphaneler inşa aşamasına libPods.a eklemek zorunda kaldı.

Umarım bu başka birine yardım edebilir.


Parlak! Birim testi için MagicalRecord ve ayrıca OCMockito ve OCHamcrest kullanıyorum. Bu düzeltme ile şimdi hepsini CocoaPods üzerinden yükleyebilirim! Teşekkürler!
Fogmeister

4
Bu benim için çalıştı, teşekkürler. NOT .. libPods.a'yı hem test projesine hem de ana projeye eklemem gerekmiyordu. Bu, yinelenen bir sembol hatasına neden olur
Craig Bruce

Benim için "Kullanıcı Tanımlı" oluşturma ayarlarını da kopyalamak zorunda kaldım. Üstbilgi Arama Yolları, test hedefinde tanımlı olmayan $ PODS_ROOT değerine başvurur. Editör-> Derleme Ayarı Ekle-> Kullanıcı Tanımlı Ayar Ekle'ye gidip $ PODS_ROOT değerini ana hedeften kopyalayarak ekleyebilirsiniz.
Shinigami

11
Bunu düzeltmenin doğru yolu bu değildir. Link_with ile cevaba bakınız. Ayrıca , pod dosyanızda her hedef için farklı kapsüller belirtebilirsiniz , yani test hedefinize yalnızca OCMockito ekleyin.
dbainbridge

Evet evet evet! Bu cevaptan önce Test hedefini projelerimden silmek zorunda kaldım! Teşekkürler adam :)
Josip B.

53

Burada bulduğum bir çözüm var CocoaPods ile Birim Testleri :

Proje dosyasını Xcode'da açın, ardından Projeyi (hedefi değil) seçin, sağ panelde Konfigürasyonlar adlı bir bölüm vardır. Test hedefiniz için "Yapılandırma dosyasına göre" sütununda Bölmeleri seçin.

resim açıklamasını buraya girin


Peki, Spectatest projesine bağlanmak istediğiniz, ancak ana projeye değil, teste özgü bağımlılıklar varsa ne olacak? : S
fatuhoku

Bu işe yaradı ve kapsül yapılandırmasında veya kurulumunda herhangi bir değişiklik gerektirmiyor ... Mükemmel çözüm.
Richard

1
Bu çözüm bir hata oluşturabilmesine rağmen: Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined. Bu durum Cocoapods'daki bir hatadan kaynaklanıyor gibi görünüyor; aşağıdaki @ RJV cevabına bakınız.
Richard

Bunlar sadece uyarılar değil. Böyle bir kurulumla uygun bir Xcode kodu kapsamı verisi üretilmez ve ünite testleri çoğu durumda başlatma sırasında askıda kalır.
16:10, i4niac

Estimote SDK'yı sürükleyip bırakarak manuel olarak içe aktardım, bakla almıyorum. Bu nasıl çözülür?
Guru Teja

18

Kütüphanelerin test hedefleriyle bağlantılandırılması gerektiğini söyleyen diğer cevaplara katılıyorum. Ancak şimdiye kadar hiçbir öneri bana yardımcı olmadı. @Fabb bir yorumda yazdığı gibi: "test ederken, isSubclassOfClass:çağrılar EVET'i döndürmeleri gereken yere NO döndürür. Bunu açıklayabilmemin tek nedeni, bağımlılıkların hem ana hem de test hedefine ve test hedefinin paketine ne zaman bağlanacağıdır. yükleyici ana paketi yüklerse, hangi sınıfı alacağına karar veremez. " Bu konuda daha önceki tüm önerileri ile aynı sorunu alıyorum.

Çalışmam gereken çözüm, ana hedefim ve test hedefim için belirli Pod'ları tanımlamak üzere Pod dosyamı güncellemekti:

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

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

O was gerekli herhangi bir test spesifik Pod'larını kullanmak olmamasına rağmen benim test hedefi için bir Pod belirtmek için. Aksi takdirde CocoaPods projeme gerekli bağlantı mantığını eklemezdi.

Bu bağlantı bu sonuca varmamda bana yardımcı oldu.


1
CocoaPods sorununun bağlantısı için teşekkürler - sorunumu çözmeme yardımcı oldu!
karlbecker_com

EVET!!!! Bu sorun beni rahatsız ediyor. Karşılaştığım tek mantıklı cocoapods cevabı bu.
DonnaLea

Bunu 1.x altında ele almanın daha iyi bir yolu var: stackoverflow.com/a/40866889/2799670
Darren Black

6

:exclusive => trueUygulama testi hedefinde yinelenen simge hatalarını önlemek için ekledim .

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

link_with 'myProject', 'myProjectTests'

Uygulama testi hedefini mantık birimi testi olanına değiştirdiğimde bağlayıcı hatası oluşuyor. Çıkardıktan sonra :exclusive => trueher şey tekrar çalışıyor.

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

link_with 'myProject', 'myProjectTests'

:exclusive => truedışında kalan her şeyin do...endBAĞLANMAMASI gerektiğini belirtir myProjectTests, bu da uygulama testi hedeflerinde mantıklıdır, ancak mantık testi hedeflerinde bağlayıcı hatalarına neden olur.



1
Evet, herkes bu sorunu @karlbecker_com ile bağlantılı github'da okumalıdır. Bu sadece kocoapodların uzun süren bir sınırlaması gibi görünüyor. Oradaki tartışmaya göre link_with gerekli değil. Sadece test hedefini ekleyin ve kullanın: özel. Test hedefinizin herhangi bir özel kapsüle ihtiyacı yoksa, yine de bir tane ekleyin, aksi takdirde cocoapods bunu işlemez.
kball

@kball Hangisinin link_with'e ihtiyacı yok? Uygulama testi veya mantık birimi testi?
Hai Feng Kao

Kullanmak için başka bir nedeniniz yoksa, link_with'e hiç ihtiyacınız olmamalıdır. Ve genel olarak konuşursak, bu bölmeleri test paketinize bağlamak istemezsiniz. Uygulama paketinde yalnızca bir kez bağlanmalı ve daha sonra bağımlılık yoluyla testleriniz tarafından referans gösterilmelidir (Varsayılan olarak Gizli Sembollerin kapalı olduğundan emin olun). Aksi takdirde, kapsülün iki sürümü bulunacağı için davranış tanımlanmamıştır - biri uygulama hedefine, diğeri test hedefine dahil.
kball

6

@Keith Smiley çözümüne göre link_with kullanabilirsiniz.

Her bir hedef için ortak kapsülünüz ve spesifikasyonlarınız varsa, kapsül grubunu tanımlamak için "def" seçeneğini kullanmak isteyebilirsiniz. ve daha sonra özel hedefte "def" kullanın.

def import_pods
    pod 'SSKeychain'
end

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

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

yukarıdaki örnekte, her iki hedefe 'SSKeychain' ve yalnızca 'MyProject' hedefine 'Typhoon' ekledim


5

Bu soruna çözümüm, Podfile'mi kütüphaneyi böyle iki hedefe dahil edecek şekilde değiştirmekti

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

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

Hızlı kullandığım için test hedefini de MyApp-Bridging-Header.hdosyayı içerecek şekilde yapılandırmak zorunda kaldım . (Derleme Ayarları sekmesinin altındaki Swift Derleyici grubunda)


3
Dikkatli olun - bu, daha fazla kapsül eklemeye devam ettiğiniz için derleme sürelerinizi çok artıracaktır!
fatuhoku

@fatuhoku bunu bilmiyordu. İnşa süresini neden arttırdığına dair biraz fikir verebilir misiniz?
Qw4z1

2
Bir kapsülün her sözü Podsprojenizdeki bir hedeftir . Bölmelerinizden iki kez bahsederek (bir kez testler ve bir kez uygulama için), iki hedef setiniz olacaktır. Bu, yapılandırma işinin pod installyapması gereken etkin bir şekilde iki katına çıkar . 15'ten fazla kapsülü olana kadar bu bir sorun olmayacak, bu yüzden o zamana kadar çok endişelenmeyin.
fatuhoku

1
Bu benim için Cocoapods 1.0 ile çalışan tek çözüm
William Entriken

1.x itibariyle, bu, uygulama bağımlılıklarını devralan testler için resmi yöntemdir: stackoverflow.com/a/40866889/2799670
Darren Black

4

Bazı sürüm denetimi sırasında bazı kütüphane dosyalarını kaybettiğimde de benzer bir olay yaşadım. Hala Pod'larımda kütüphane dosyasını gördüm ama gerçek kod eksikken, XCode gittiğini söyledi. Benim dehşete, 'pod install' çalıştırmak kayıp dosyaları hemen geri getirmiyordu.

Aşağıdakileri yaparak podu manuel olarak çıkarmak ve değiştirmek zorunda kaldım:

  1. Kütüphaneyi Pod dosyasından kaldırma
  2. Kütüphaneyi tamamen kaldırmak için 'pod install' komutunu çalıştırın
  3. Kütüphaneyi tekrar Pod dosyasına yerleştirin
  4. 'Pod yükleme'yi tekrar çalıştırın

Bu, söz konusu kütüphaneyi orijinal haline getirmelidir.


2

Ayrıca libPods.a, iki kez eklediyseniz, böyle kötü bir hata alacağınızı belirtmek gerekir :

232 duplicate symbols for architecture i386

Düzeltmek libPods.aiçin Proje Gezgini'ndeki referanslardan birini silin .


2

CocoaPods 1.x'ten itibaren, bir hedef ile karşılık gelen test hedefi arasında paylaşılan bağımlılıkları bildirmenin yeni bir yolu vardır. Bu noktaya kadar Mark Struzinski tarafından kabul edilen çözümü kullanıyordum, ancak bu yöntemi kullanarak testlerimi çalıştırırken çok sayıda uyarı verdim:

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 ile -Test hedefimizi aşağıdaki gibi ana hedefin arama yollarından devralma olarak ilan edebiliriz:

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

Bu, -Test hedefinin birden çok ikili kopya olmadan uygulama hedefinin bağımlılıklarına erişmesine neden olur. Bu benim için test oluşturma sürelerini ciddi şekilde hızlandırdı.



1

Swift uygulamamla iOS'ta GoogleMaps Objective-C POD entegrasyonu ile çalışıyorum ve bu yüzden benim için sorun, Test hedefinin Yapı Ayarlarında Köprü Üstbilgisi Dosyasına ( SWIFT_OBJC_BRIDGING_HEADER ) bir referans olmamasıydı . Hızlı uygulama testlerinde 3. taraf API çağrılarının (harita API'sı vb.) Kullanılabilmesi için hem uygulamanızın hem de test uygulama hedeflerinizin bunu gösterdiğinden emin olun.


1
Seninle benzer bir düzenim var. Zaten köprü hedefini test hedefine ekledim, ancak "Böyle bir modül 'GoogleMaps'" hatası alıyorum import GoogleMaps.
Nicolas Miari

0

Sonraki sözdizimi benim için en iyi sonucu veriyor (cocoapod v.1.2.1 altında test edildi):

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

Bu olmadan test yinelenen semboller hakkında uyarıları var.

Bundan sonra uyarılar kayboldu.


0

XCTest altında OpenCV kullanırken sorunlar yaşadım. Bana Undefined symbols for architecture arm64gibi sınıflar için bağlayıcı hatalar veriyordu cv::Mat. OpenCV'yi pod 'OpenCV', '~> 2.0'ana hedef altında CocoaPods üzerinden kuruyorum . OpenCV bağımlılığını test hedefinin altına koymaya ya da inherit! :search_pathshiçbirini kullanmaya çalışmamın önemi yok. Çözüm şöyle bir şey yaratmaktı 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 

Ayrıca , projeyi temizlemeye yardımcı olan pod deintegrate& pod cleantest ederken yeni başladığınızdan emin olmanıza yardımcı olan & komutları da yararlıdır . Bu ikisini kullanarak kurabilirsiniz [sudo] gem install cocoapods-deintegrate cocoapods-clean.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.