My Cocoapod's lib project fails its tests on Travis because the test target seems to be unable to find one of the Pod's sources:
'XYZMyClass.h' file not found
On my development environment, I can run the same command Travis is running successfully and the environments are set the same:
osx_image: xcode8
for Travis and I use Xcode 8.0 locally as wellThe instruction that fails on Travis but runs successfully locally is the following:
set -o pipefail && xcodebuild -workspace Example/XYZMyPod.xcworkspace -scheme XYZMyPod-Example -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6s,OS=9.3' test | xcpretty
Even weirder, the 'XYZMyClass.h' is the 2nd import in my source file imports. Why does the 1st one works OK? They belong to the same target, with the same visibility (Public
).
PS: the source is available on GitHub here and the Travis build is here.
Thank you!
The root of problem lies in your BSGMetrics.podspec
Upon pod install, these headers get public:
s.public_header_files = [
'BSGMetrics/Classes/BSGMetrics.h',
'BSGMetrics/Classes/BSGMetricsConfiguration.h',
'BSGMetrics/Classes/BSGMetricsEvent.h'
]
That is why in your test class you are able to see first import and not able to see second import.
#import "BSGMetricsEvent.h"
#import "BSGMetricsService.h"
If the service is intended to be private header, you won't be able to test it with this kind of installation - via Sample project with tests target and your pod installed as pod.
Instead you need to have your pod files added to project's main or test target (and I suggest test, not main).
Anyway, the simplest workaround here is to expose BSGMetricService
into s.public_header_files
EDIT (Description on testing approaches):
The trick is how you treat unit tests. Think of BSGMetrics as of "module", a blackbox. It has some "visible" interface and some hidden implementation details. This is true for both Objective-C and Swift. The different is the language tools used to define visibility of your module entities. In Objective-C it's header files. In Swift it's public
, private
, internal
modifiers (before Swift 3.0)
So, until you treat your BSGMetrics as a module while testing, you won't be able to access / test your implementation details. You will be able to test it only via available interface.
Is it bad or good? Not really, everything depends on what you need. However, if your expect on [BSGMetrics openWithConfiguration:]
to have instance of BSGMetricsService
initialized, you need BSGMetricsService
to be visible to scope of your test. And there are two approaches: make is visible (the way you used for now) or merge module and test's scopes.
I'll describe a bit how I achieve the latter approach for testing one of my libraries.
First, test target is the part of same project, where all files under test are added as well.
Second, testing is done only inside test bundle, without host application.
Third, files under test are added to compile in test target as well.
So long story short, tests and code under tests reside in same module.
More reading might be found here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With