Nie znaleziono bibliotek podczas używania CocoaPods z testami logiki systemu iOS

148

Próbuję napisać kilka testów logicznych iOS dla klas w moim projekcie, które używają funkcjonalności z niektórych bibliotek w moim podspec. Używam standardowego pakietu testów jednostkowych dostarczonego w Xcode (chociaż nie testów aplikacji, tylko testy jednostkowe).

Na przykład używam Magical Record i mam tę bibliotekę połączoną w moim podspec. Jest obecny w projekcie Pods w moim obszarze roboczym i działa zgodnie z oczekiwaniami, gdy aplikacja jest uruchomiona w symulatorze lub na urządzeniu. Kiedy jednak próbuję połączyć z testem obiekt, który używa Magical Record, pojawia się błąd linkera informujący, że nie może znaleźć selektorów z Magical Record. Próbowałem zaktualizować ścieżkę HEADER_SEARCH_PATH w moim pakiecie testowania logiki, nawet mocno zakodowałem ją w katalogu nagłówków utworzonym przez CocoaPods, ale bez powodzenia.

Mogę bez problemu przeprowadzić testy jednostkowe dla klas, które nie używają bibliotek CocoaPods.

Czy robię to źle? Czy powinienem zrobić coś innego, aby kompilator mógł zobaczyć biblioteki CocoaPods?

Mark Struzinski
źródło

Odpowiedzi:

224

CocoaPods 1.0 zmieniła składnię tego. Teraz wygląda to tak:

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

target 'Sail' do
    shared_pods
end

target 'Sail-iOS' do
    shared_pods
end

Odpowiedź sprzed wersji CocoaPods 1.0

To, czego chcesz użyć, pochodzi link_withz twojego Podfile. Coś jak:

link_with 'MainTarget', 'MainTargetTests'

Następnie biegnij pod installponownie.

Keith Smiley
źródło
7
To natychmiast rozwiązało problem.
mttrb
9
Otrzymuję z tym dziwne błędy - podczas testowania isSubclassOfClass:połączenia wracają NOtam, gdzie powinny YES. Jedynym powodem, dla którego mogę to wyjaśnić, jest to, że zależności są naprawdę połączone zarówno z głównym, jak i testowym celem, a kiedy program ładujący pakiet celu testowego ładuje pakiet główny, nie może zdecydować, którą klasę wybrać.
fabb
4
Mam ten sam problem z isKindOfClass:powrotem, NOkiedy powinien wrócić YES. Jeśli zarejestruję wskaźnik do Classobiektu, który testuję, i Classklasy, z którą chcę porównać, będą to dwie różne wartości. Oczywiście mój kod z pakietu aplikacji używa innego symbolu dla klasy niż kod z moich testów jednostkowych. Czy ktoś znalazł sposób na rozwiązanie tego problemu?
Nicholas Hart
2
Nie sądzę, żeby to była dobra droga ze względu na błędy, o których wspominali inni. Pozostań przy aktualizacji pliku konfiguracyjnego „na podstawie” bit. Upewnij się, że nie podłączyłeś dwukrotnie libPods.a.
Bob Spryn
3
Powinna to być akceptowana odpowiedź, ponieważ jest to oficjalny sposób CocoaPods do ustawiania podów z wieloma celami. Wielkie dzięki Keith!
cschuff
174

Zrozumiałem to, sprawdzając, jak głównym celem mojej aplikacji było odbieranie ustawień z biblioteki CocoaPods. CocoaPods zawiera plik .xcconfig o nazwie Pods.xcconfig. Ten plik zawiera wszystkie ścieżki wyszukiwania nagłówków.

Jeśli spojrzysz na swój projekt w nawigatorze projektów i klikniesz kartę Informacje, w górnej sekcji zobaczysz konfiguracje kompilacji. Jeśli otworzysz trójkąt ujawniania dla różnych konfiguracji, zobaczysz pody wymienione pod głównym celem. Musiałem kliknąć menu i dodać pody do celu testu logicznego.

Migawka konfiguracji

Miałem też skopiować ustawienia $(inherited)i ${PODS_HEADERS_SEARCH_PATHS}od mojego głównego celu i skopiować je do celu testu logika obszarze Ustawienia Build / HEADER_SEARCH_PATHS.

Na koniec musiałem dodać libPods.a w fazie kompilacji Link Binary with Libraries dla mojego celu testów logicznych.

Mam nadzieję, że to może pomóc komuś innemu.

Mark Struzinski
źródło
Znakomity! Używam MagicalRecord, a także OCMockito i OCHamcrest do testów jednostkowych. Dzięki tej poprawce mogę teraz zainstalować je wszystkie za pośrednictwem CocoaPods! Dzięki!
Fogmeister
4
To zadziałało dla mnie, dzięki. UWAGA .. Nie musiałem dodawać libPods.a zarówno do projektu testowego, jak i głównego. Powoduje to podwójny błąd symbolu
Craig Bruce,
W moim przypadku musiałem również skopiować ustawienia kompilacji „Zdefiniowane przez użytkownika”. Ścieżki wyszukiwania nagłówków odnoszą się do $ PODS_ROOT, który nie został zdefiniowany w celu testowym. Możesz go dodać, przechodząc do Editor-> Add Build Setting-> Add User-Defined Setting, a następnie kopiując wartość $ PODS_ROOT z głównego celu.
Shinigami,
11
To nie jest właściwy sposób rozwiązania tego problemu. Zobacz odpowiedź z link_with. Możesz także określić różne pody dla każdego celu w swoim pliku pod, tj. Uwzględnij tylko OCMockito w celu testowym.
dbainbridge
Tak tak tak! Przed tą odpowiedzią musiałem usunąć cel testowy z moich projektów! Dzięki stary :)
Josip B.
53

Jest rozwiązanie, które znalazłem tutaj Testy jednostkowe z CocoaPods :

Otwórz plik projektu w Xcode, a następnie wybierz projekt (nie cel), w prawym panelu znajduje się sekcja o nazwie Konfiguracje. Wybierz Pods w kolumnie „Na podstawie pliku konfiguracyjnego” dla celu testowego.

wprowadź opis obrazu tutaj

Mingming
źródło
A co, jeśli istnieją zależności specyficzne dla testu, takie jak Spectate, które chcesz połączyć z projektem testowym, ale nie z projektem głównym? : S
fatuhoku
To zadziałało i nie wymaga żadnych zmian w konfiguracji lub konfiguracji poda ... Doskonałe rozwiązanie.
Richard
1
Chociaż to rozwiązanie może spowodować błąd: Class Foo is implemented in both MyApp and MyAppTestCase. One of the two will be used. Which one is undefined. Wydaje się, że jest to spowodowane błędem w Cocoapods; zobacz odpowiedź @JRV poniżej.
Richard
To nie są tylko ostrzeżenia. Przy takiej konfiguracji nie są generowane odpowiednie dane pokrycia kodu Xcode, a testy jednostkowe po prostu zawieszają się podczas uruchamiania w większości przypadków.
i4niac
Zaimportowałem Estimote SDK ręcznie przez przeciąganie i upuszczanie, nie otrzymuję podów. Jak rozwiązać ten problem?
Guru Teja
18

Zgadzam się z innymi odpowiedziami, mówiąc, że konieczne jest powiązanie bibliotek z celami testowymi. Jednak żadna z dotychczasowych sugestii nie pomogła mi. Jak pisze @fabb w komentarzu: „podczas testowania isSubclassOfClass:wywołania zwracają NIE, a powinny zwracać TAK. Jedynym powodem, dla którego mogę to wyjaśnić, jest to, że zależności są naprawdę połączone zarówno z głównym, jak i testowym celem, a także gdy pakiet celu testowego loader ładuje główny pakiet, nie może zdecydować, którą klasę wybrać. " Mam ten sam problem ze wszystkimi poprzednimi sugestiami w tym wątku.

Rozwiązaniem, które dostałem do pracy, było zaktualizowanie mojego pliku Podfile, aby zdefiniować określone pody dla mojego głównego celu i celu testowego:

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

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

Było to konieczne , aby określić POD dla mojego cel testu, mimo że nie używaliśmy żadnych testów konkretnych strąków. W przeciwnym razie CocoaPods nie wstawiłby niezbędnej logiki łączenia w moim projekcie.

Ten link pomógł mi dojść do takiego wniosku.

JRV
źródło
1
Dziękuję za link do problemu CocoaPods - to pomogło mi rozwiązać mój problem!
karlbecker_com,
TAK!!!! Ten problem mnie dręczy. To jedyna rozsądna odpowiedź na cocoapody, z jaką się spotkałem.
DonnaLea
Jest lepszy sposób na rozwiązanie tego problemu pod 1.x: stackoverflow.com/a/40866889/2799670
Darren Black
6

Dodałem, :exclusive => trueaby uniknąć zduplikowanych błędów symboli w celu testu aplikacji.

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

link_with 'myProject', 'myProjectTests'

Kiedy zmieniłem cel testu aplikacji na test jednostki logicznej, pojawia się błąd konsolidatora. Po usunięciu :exclusive => truewszystko znów działa.

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

link_with 'myProject', 'myProjectTests'

:exclusive => truestwierdza, że ​​wszystko na zewnątrz do...endNIE powinno być powiązane myProjectTests, co jest rozsądne w przypadku celów testów aplikacji, ale spowoduje błędy konsolidatora w celach testów logicznych.

Hai Feng Kao
źródło
Ekskluzywne było dla mnie rozwiązanie, jak pokazano w odpowiedzi Kylefa na ten problem CocoaPods , która została znaleziona dzięki odpowiedzi JRV na to pytanie!
karlbecker_com
1
Tak, każdy powinien przeczytać ten numer na githubie, do którego prowadzi @karlbecker_com. Wygląda na to, że to tylko długotrwałe ograniczenie kokoapodów. Zgodnie z tamtą dyskusją link_with nie jest konieczny. Po prostu dodaj cel testu i użyj: wyłączne. Jeśli twój cel testowy nie potrzebuje żadnych konkretnych strąków, dodaj jeden, w przeciwnym razie cocoapod go nie przetworzy.
kball
@kball Który z nich nie potrzebuje link_with? Test aplikacji czy test jednostki logicznej?
Hai Feng Kao
Jeśli nie masz innego powodu, aby go używać, nie powinieneś w ogóle potrzebować linku_with. I ogólnie rzecz biorąc, nie chcesz łączyć tych podów z pakietem testowym. Powinny być połączone tylko raz, w pakiecie aplikacji, a następnie przywoływane w testach za pośrednictwem zależności (upewniając się, że symbole ukryte domyślnie są wyłączone). W przeciwnym razie zachowanie jest niezdefiniowane, ponieważ będą istnieć dwie wersje podów - jedna zawarta w celu aplikacji, a druga w celu testowym.
kball
6

Możesz użyć link_with zgodnie z rozwiązaniem @Keith Smiley.

Jeśli masz wspólne pody i specyfikacje dla każdego celu, możesz użyć opcji „def”, aby zdefiniować grupę podów. i użyj "def" później w wyłącznym celu.

def import_pods
    pod 'SSKeychain'
end

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

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

w powyższym przykładzie dodałem „SSKeychain” do obu celów, a „Typhoon” tylko do celu „MyProject”

Elihay
źródło
5

Moim rozwiązaniem tego problemu była zmiana mojego pliku Podfile, aby włączyć bibliotekę do obu celów, takich jak ten

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

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

A ponieważ używam swift, musiałem również skonfigurować cel testowy, aby uwzględnić MyApp-Bridging-Header.hplik. (W grupie Swift Compiler na karcie Ustawienia kompilacji)

Qw4z1
źródło
3
Ostrożnie - to znacznie wydłuży czas budowy, ponieważ będziesz dodawać kolejne zasobniki!
fatuhoku
@fatuhoku tego nie wiedział. Czy możesz wyjaśnić, dlaczego wydłuża to czas kompilacji?
Qw4z1,
2
Cóż, każda wzmianka o kapsule jest celem w twoim Podsprojekcie. Wymieniając dwukrotnie swoje pody (raz w przypadku testów i raz w przypadku aplikacji), będziesz mieć dwa zestawy celów. To skutecznie podwaja prace konfiguracyjne pod install. Nie będzie to problemem, dopóki nie będziesz mieć> 15 kapsułek, więc nie martw się zbytnio do tego czasu.
fatuhoku
1
To jedyne rozwiązanie, które działa dla mnie z Cocoapods 1.0
William Entriken
Od wersji 1.x jest to oficjalna metoda testów dziedziczących zależności aplikacji: stackoverflow.com/a/40866889/2799670
Darren Black
4

Miałem podobne zdarzenie, gdy zgubiłem niektóre pliki biblioteczne podczas kontroli wersji. Nadal widziałem plik biblioteki w moich Podach, ale z brakującym kodem XCode powiedział, że zniknął. Ku mojemu przerażeniu uruchomienie „instalacji pod” nie przywróciło od razu utraconych plików.

Musiałem ręcznie usunąć i wymienić kapsułę, wykonując następujące czynności:

  1. Usuń bibliotekę z pliku Podfile
  2. Uruchom „pod install”, aby całkowicie usunąć bibliotekę
  3. Umieść bibliotekę z powrotem w Podfile
  4. Uruchom ponownie „pod install”

Powinno to przywrócić daną bibliotekę do jej pierwotnej formy.

Maxwell
źródło
2

Warto również zauważyć, że jeśli libPods.adodałeś dwa razy, pojawi się taki nieprzyjemny błąd:

232 duplicate symbols for architecture i386

Aby to naprawić, po prostu usuń jedno z libPods.aodniesień w Eksploratorze projektów.

Mat Ryer
źródło
2

Począwszy od CocoaPods 1.x, istnieje nowy sposób deklarowania współdzielonych zależności między celem a odpowiadającym mu celem testowym. Do tej pory korzystałem z przyjętego rozwiązania Marka Struzińskiego, ale użycie tej metody przyniosło ogromną liczbę ostrzeżeń podczas przeprowadzania moich testów, które:

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.

Dzięki CocoaPods 1.x możemy zadeklarować nasz cel -Test jako dziedziczący poprzez ścieżki wyszukiwania celu nadrzędnego, na przykład:

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

Spowoduje to, że obiekt docelowy -Test będzie miał dostęp do zależności celu aplikacji bez wielu kopii binarnych. To znacznie przyspieszyło czas tworzenia testów.

Darren Black
źródło
1

Pracuję z integracją GoogleMaps Objective-C POD na iOS z moją aplikacją Swift, więc problem polegał na tym, że cel testowy nie miał odniesienia do pliku nagłówkowego mostka ( SWIFT_OBJC_BRIDGING_HEADER ) w ustawieniach kompilacji. Upewnij się, że zarówno aplikacja, jak i cele aplikacji testowej wskazują na to, aby wywołania interfejsu API innej firmy (interfejs API map itp.) Mogły być używane w szybkich testach jednostkowych.

appledevguru
źródło
1
Mam podobną konfigurację jak Ty. Dodałem już nagłówek mostkujący do celu testu, ale pojawia się błąd „Brak takiego modułu 'GoogleMaps'” import GoogleMaps.
Nicolas Miari,
0

Następna składnia daje najlepszy wynik dla mnie (testowane pod 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

Bez tego mam ostrzeżenia podczas testu o zduplikowanych symbolach.

Po tym ostrzeżenia zniknęły.

Maxim Kholyavkin
źródło
0

Miałem problemy z używaniem OpenCV pod XCTest. To dawało mi błędy linkera Undefined symbols for architecture arm64dla klas takich jak cv::Mat. Instaluję OpenCV przez CocoaPods, używając pod 'OpenCV', '~> 2.0'głównego celu. Bez względu na to, jak bardzo starałem się umieścić zależność OpenCV pod celem testowym lub inherit! :search_pathsnic z tego nie zadziałało. Rozwiązaniem było stworzenie abstract_targettakiego:

# 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 

Przydatne są również polecenia pod deintegrate& pod clean, które pomagają oczyścić projekt i upewnić się, że zaczynasz od nowa podczas testowania. Możesz zainstalować te dwa za pomocą [sudo] gem install cocoapods-deintegrate cocoapods-clean.

Foti Dim
źródło