Cocoapods: How do I unit test a Cocoapods library ?

Created on 12 Jan 2016  Â·  27Comments  Â·  Source: CocoaPods/CocoaPods

I am trying to figure out how to set up simple unit testing for my Cocoapods library.

Here is what I tried:

I added a unit testing target 'MyTestTarget' to the 'Pods' Project, edited my 'MyCocoapodLib' scheme to add the test target. Then I created classes for my unit tests with Nimble and Quick. I then added the test classes to the test target and everything went smooth, testing worked. I can now select my 'MyCocoaPodLib' scheme and press CMD+U and the testing target executes the tests. This is the behaviour I am looking for.

This approach however has some drawbacks (?). If I do 'pod update' on my example app, the test target is gone (Cocoapods probably sets up targets in the background and my target ends up lost). Also I would like to prevent the test classes from being loaded into any consumers using the library, therefore I added an exclusion to my podspec:

s.exclude_files = 'Pod/Classes/**/Test/*'

With this line I basically eliminate all test classes from being included. However, if I call pod update on my Example application, the tests are gone too. I'm certain there is a correct way to do this, this doesn't seem to cut it.

Here's the thing though:

I am unsure if this is the right way to do this because I noticed that there already is a target called 'Pods-MyCocoapodLib_Tests'. Is this an actual test target ? If so, how do I add and execute unit tests against 'MyCocoapodLib' scheme ? I would love to associate the test target with my CocoaPods library and just press CMD+U.

I apologize in advance for my limited knowledge about this, but even after searching for it extensively and consulting multiple sources I could not find any useful resources to help me shed some light on this.

Any help would be greatly appreciated.

Most helpful comment

Pigging backing on this issue.
I've setup a new (swift) pod library pod lib create XXX, added some files to the Classes folder.
I've said No to Which testing frameworks will you use? [ Quick / None ] and YES to Would you like to include a demo application with your library? [ Yes / No ] as I would like to be able to test my lib in the demo application.

I've then edited the Podfile to add my work in progress pod to the test target.

If I run unit test right away without adding any (there is the default Tests.swift file), all the test pass ;)

But if I add any test which use classes of my pod, the test suit fail right away (without actually running any test) with this mysterious error:
Test target XXX_Example encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)

Any idea?

Happy to open a new thread if it's better...

All 27 comments

Did you look at the project that pod lib create generates? It supports doing Quick / Nimble out of the box

@orta Thanks for the quick response. Yes, I initially did set the library up to use Nimble and Quick, the issue lies more in how to test in general (Title might be misleading, I apologize).

The test files should go inside the example application rather than the Pod itself - you can take a look at https://github.com/artsy/Artsy-Authentication as an example which should help I think

@orta If you are correct about this, it's really puzzling to me why I can't add unit tests to the library itself to test its core functionality. Is there any reason for this ?

@orta If you take a look at Alamofire (https://github.com/Alamofire/Alamofire) there is a Tests folder that seems to be independent from the Example application (I might be wrong though ?)

It's more a side-effect of how test bundles work with UI stuff in Xcode, in theory the project _could_ be setup to run a test bundle without a host app, but you get unreliable access to UI* classes and I'd rather it work for everyone's library than it not work out of the box by default for all cases.

@orta I am only really looking for a logical testing target, which does not take care of testing any user interface elements. Just plain logical unit testing of my models.

Then you want to make a blank Xcode project, then add a new separate test target with "no target". Then create a Podfile that hooks up to that target with your dev pod via :file ( like pod lib create does )

This is a rough version without all the pods: http://cl.ly/0F1g3G0g4647

So you say I should create a different (sub-?)project that takes care of the testing ? Could you possibly elaborate on ":file (like pod lib create does)" ?

@orta Actually I just downloaded Alamofire for further inspection and it seems as if it's not even using Cocoapods internally. For some reason it just seems really strange to me why this wouldn't be possible with Cocoapods (adding a test target that persists across updates). I can't go the same route as Alamofire because I need Cocoapods' features like dependencies etc. I just can't wrap my head around this whole thing...

The main issue is that you can only test targets which are defined in the same project, so your test bundle would need to be added to the Pods project, not the application project, if you want to go the same route as Alamofire.

You can however go the route @orta suggested and add your Pod as a dependency of a new test target that resides in the application project.

@neonichu Understood. Can you elaborate on how to do this exactly ? Should I create a new subproject, add a podfile with my pod as a dependency and create a test target in there ?

that really depends on your preferences — you can also just add a new test target in the existing project and add an additional target block to your existing Podfile

@neonichu That's what I originally intended to do. From the conversation I thought this wouldn't be possible. I stated in the original issue that I did just that, but on pod update I would have the target vanish. I don't know how to proceed from adding a unit testing target, then linking that to my pod target. Also as originally pointed out, I would like the tests to not be included into my clients' projects, but if I specify 'exclude_files' in my podspec the files vanish in the original pod as well. Or should I just not call pod update on my Example project ?

If you don't want the test target in the client project, you should create an additional project as you suggested. Anything you add to the Pods project will be overwritten by the next pod install or pod update.

The Pods structure is not meant to be touched, he means to your project. You need to have a separate xcodeproject that holds things like the test target + tests.

@orta @neonichu Okay, that actually makes sense. So, once I added the empty XCode project and set up a test target, what should I do next ?

@thecritic I've provided an example project above of this structure, I think you should do some research + try some ideas before coming back to this thread. We use issues as a bug + feature tracker, not as Stack Overflow.

@orta Sorry did not mean to be so intrusive. I prefer to ask here because I haven't been very successful getting satisfying answers regarding Cocoapods on SO in the past. I deeply apologize and with that said I think you can close this.

P.S. Took another look at the sample you provided. I guess I just have to setup a Podfile in there and add my development pod + call pod update to load it in. Then I can test that. It just really seems counter-intuitive this way (the whole "another project"-thing), but if has to be that way, then I guess I'll have to go with that.

Thanks for your splendid support, really appreciate your help guys.

@orta @neonichu By the way before we close this, is it common practice to test the classes in the example project ? The reason I came here is to make sure I do this the right way and if you say that testing the pod's classes in the example project is common practice I would actually prefer common practice over what I think should be the right way to do this.

Yeah, no worries. No need for apologising. So the example is the common practice ( I do this in every library I work on. ) Given that we're using common Cocoa building blocks, there are many options for putting it together though, but in the end we have to make it run how Xcode wants it to.

This is one that provides the most for the least amount of hassle. Which is why it's the most common, though it does get the network effect of being the default from pod lib create. I did build that based on looking at a lot of libraries in the ecosystem and taking the best ideas.

@orta So just to be clear, you add your testing code for the library itself into the Example project that is provided by pod lib create, right ? I am a little confused with the ambiguous term "Example", because you provided an example for the blank XCode project above (regarding my use-case), but there is also the "Example" project within the workspace provided by cocoapods). I am almost certain that you mean you add it to the Example project provided by pod lib create, can you confirm if my thinking is correct ?

@orta Never mind, I think I got it. Thanks for the support again and pointing me into the right direction.

Pigging backing on this issue.
I've setup a new (swift) pod library pod lib create XXX, added some files to the Classes folder.
I've said No to Which testing frameworks will you use? [ Quick / None ] and YES to Would you like to include a demo application with your library? [ Yes / No ] as I would like to be able to test my lib in the demo application.

I've then edited the Podfile to add my work in progress pod to the test target.

If I run unit test right away without adding any (there is the default Tests.swift file), all the test pass ;)

But if I add any test which use classes of my pod, the test suit fail right away (without actually running any test) with this mysterious error:
Test target XXX_Example encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted)

Any idea?

Happy to open a new thread if it's better...

@thecritic Hey I was wondering if you ever figured out how to unit test your library? I still can't wrap my head around how to actually test the internal methods of the library without marking everything 'Open' so the Example Target can see it. I know I am missing something...any help would be greatly appreciated!

@AndyMeagher I guess you just have forgotten add @testable, if you use Swift.

@Scyano You are 100% correct. Thank youuuu

Was this page helpful?
0 / 5 - 0 ratings

Related issues

intelliot picture intelliot  Â·  3Comments

evermeer picture evermeer  Â·  3Comments

pronebird picture pronebird  Â·  3Comments

5SMNOONMS5 picture 5SMNOONMS5  Â·  3Comments

soleares picture soleares  Â·  3Comments