pivotal-legacy / PivotalCoreKit

Shared library and test code for iOS and macOS projects
http://pivotallabs.com
Other
168 stars 85 forks source link

Using PivotalCoreKit in a project with code in objC and swift #193

Closed juliozatarain closed 7 years ago

juliozatarain commented 8 years ago

We are trying to integrate swift into our project. When we try to use fakes such as PSHKFakeHTTPURLResponse in our tests we get an error while installing the bundle to the simulator:

"Failed to load test bundle from file: Symbol not found: _OBJCCLASS$_PSHKFakeHTTPURLResponse"

It seems to be looking for the symbols inside the App symbols, instead of the Spec symbols.

Here is our Podfile:

source 'https://github.com/CocoaPods/Specs.git' use_frameworks!

target 'app' do pod 'Blindside' pod 'Flurry-iOS-SDK' pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git' pod 'KSDeferred' pod 'PivotalCoreKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'TrustKit' end

target 'Specs' do pod 'Blindside' pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git' pod 'KSDeferred' pod 'Cedar' pod 'Nimble', '3.2.0' pod 'PivotalCoreKit/Foundation', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'PivotalCoreKit/UIKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'TrustKit' end

Does PivotalCoreKit support a project with objC & swift code and tests together?

tjarratt commented 8 years ago

Thanks for opening this issue. Continued support for projects transitioning from objc to swift has been an important feature for a while.

I'm a little surprised to see this exact error. I'll have to dig into how that class is linked to understand it better. It might be as simple as it missing from the umbrella header for the project it belongs to.

Sent From A Very Small Keyboard

On Sep 12, 2016, at 08:15, Julio zatarain notifications@github.com wrote:

We are trying to integrate swift into our project. When we try to use fakes such as PSHKFakeHTTPURLResponse in our tests we get an error while installing the bundle to the simulator:

"Failed to load test bundle from file: Symbol not found: OBJC_CLASS$_PSHKFakeHTTPURLResponse"

It seems to be looking for the symbols inside the App symbols, instead of the Spec symbols.

Here is our Podfile:

source 'https://github.com/CocoaPods/Specs.git' use_frameworks!

target 'app' do pod 'Blindside' pod 'Flurry-iOS-SDK' pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git' pod 'KSDeferred' pod 'PivotalCoreKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'TrustKit' end

target 'Specs' do pod 'Blindside' pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git' pod 'KSDeferred' pod 'Cedar' pod 'Nimble', '3.2.0' pod 'PivotalCoreKit/Foundation', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'PivotalCoreKit/UIKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git' pod 'TrustKit' end

Does PivotalCoreKit support a project with objC & swift code and tests together?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

juliozatarain commented 8 years ago

Thanks for the quick response, so the error says that the symbol is expected in the .app: Expected in : ".app/Frameworks/PivotalCoreKit.framework/PivotalCoreKit"

I tried it using cocoapods version 0.39.0 and 1.1.0.beta.1 and I am getting the same error.

if I add the PCK foundation directory to the app target in the Podfile, then the symbol is found. But it is actually included when running the app itself so it uses the Foundation fakes instead of the real objects.

Are the tests frameworks supposed to be copied to that location?

mgoovaer commented 8 years ago

Any update on this issue?

tjarratt commented 8 years ago

Are the tests frameworks supposed to be copied to that location?

Absolutely not. It shouldn't be necessary to add your test dependencies to your app in order for your tests to run correctly.

It sounds like you're using a Test Bundle, @juliozatarain -- is that correct? Do you invoke your tests by striking cmd+u in Xcode, or by selecting your test scheme and typing cmd+r?

If you're using a test bundle, then I think some additional work is necessary to make sure the frameworks specifically for your tests load when running your tests (and I forget how to do that, so I'd need to look at xcode's project settings and reverse engineer how to do it again). This is pretty complicated when using Cocoapods, since it really, REALLY wants to overwrite your project settings on your behalf, although it's possible.

I'm going to investigate how this actually works by setting up a small reproducible project. It would be nice to have a project that demonstrates how to use PCK in a mixed objc-swift world.

You may be interested in looking at this relevant cocoapods issue -- it might point you in the right direction for xcode project settings to change to make your tests compile again.

juliozatarain commented 8 years ago

We are using a test bundle, we tried was is suggested in the cocoapods issue link and it seems to be working with cmd + u.

UPDATE: False alarm it does not work using cmd + u and xcode 8.

juliozatarain commented 7 years ago

How can we approach moving away from a test bundle? @tjarratt

tjarratt commented 7 years ago

The general approach for running without a test bundle is

In order to run your tests, you would select the SpecSuite target in Xcode, then hit cmd+r. You won't see the nice bezel appear telling you that the tests passed or failed, but you will get console output.

I prefer this approach personally because of how complicated Test Bundles with resources and extra frameworks end up being. Few people that I have met actually know how test bundles work, and it's kind of scary and amazing that Apple has been able to keep them functional for so long.

The approach that I've laid out above, while complicated and with some downsides (like not being able to use cmd+u and needing to switch targets), comes with the upside of having a simpler model -- your tests are just a separate application target, not a magical test bundle. This is a lot closer to what other languages do (ruby, go, javascript, elm, scala, java, c, c++, etc). I've never seen another language actually use anything like Test Bundles before I started doing OS X and iOS development.

tjarratt commented 7 years ago

Thinking about this some more, it sounds suspiciously similar to some other cocoapods issues that I've seen in the past.

It may have something to do with adding multiple copies of frameworks to both your specs and app targets.

Your podfile, truncated for clarity...

target 'app' do
  pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git'
  pod 'KSDeferred'
  pod 'PivotalCoreKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git'
end

target 'specs' do
  pod 'MBProgressHUD', :git => 'https://github.com/gudatcomputers/MBProgressHUD.git'
  pod 'KSDeferred'
  pod 'PivotalCoreKit', :git => 'https://github.com/pivotal/PivotalCoreKit.git'
end

This ends up (probably) creating a duplicate version of each framework into your Specs test bundle. When you run your tests, Xcode runs your real app, and then injects each test bundle that your scheme's test action specifies at runtime. At that point, each class in the test bundles will be loaded into your app's runtime, potentially creating copies of existing classes (e.g.: there will be two classes called KSDeferred (for example), but they will be distinct class instances).

My guess is that having doubled pods in your targets, combined with use_frameworks! (which you needed for swift support) may be causing this problem, although it's really hard to actually verify without a minimal reproducible test case.

tjarratt commented 7 years ago

The easy change you might want to try is not including ALL of PivotalCoreKit in your app target. If you can specify that you only want to restrict the app to, say, Foundation/Core, you might be able to get it to load PivotalCoreKit/Foundation/PivotalSpecHelper for your test target.


#other pods omitted for brevity
target 'app' do
  pod 'PivotalCoreKit/Foundation/Core', :git => 'https://github.com/pivotal/PivotalCoreKit.git'
end

target 'Specs' do
  pod 'PivotalCoreKit/Foundation/SpecHelper', :git => 'https://github.com/pivotal/PivotalCoreKit.git'
end
juliozatarain commented 7 years ago

So I followed the steps to move away from the TestBundle and we are getting the following error when running it:

ld: framework not found XCTest for architecture x86_64

I am going to try being more specific with the inclusions and see what happens.

thanks!

juliozatarain commented 7 years ago

So we kept the bundle approach and just stopped using PCK in the app target. And its working now.