CocoaPod issue with test target - ios

I have a helper class (GoogleHelper) in swift that uses the Google finance API where I use AFNetworking for Google API call. AFNetworking is imported using cocoa pods.
I need to test the GoogleHelper and need mocking.
For mocking to work, I have to add the GoogleHelper file to test target as well. and redefine a mock class in the test class.
class MockGoogleHelper: GoogleHelper {
override func getSymbol(text: String) -> String {
return "symbol"
}
}
The issue is that the test target has compiling issues with AFNetwork. I added the header files and the compiled pod library manually to the test target but the issue persist.
I have two questions?
how to make the cocoa pods add the dependency to the test target. I have used linked_with in my pod file but no luck
If there is any hint on the way I am setting my test wrong let me know as I think when I test my helper class it should not depend on the AFNetworking but I am not sure how to eliminate the dependency.

There are a couple of things you should do to get it to work:
add the test target to your pod file e.g. linked_with 'myprj', 'myprjTests'
in project/info/configuration for both debug and release select Pods.debug or Pods.release respectively.
you need to bridge your library if project is on swift and the library imported with cocoa pods is in objective c. to do so just try to add an objective c file to your test files and Xcode will automatically add the bridging header to your project.

Related

iOS Swift framework: How to import Objective C code into swift framework properly?

I have an umbrella header called
MyApp-Swift.h
I've imported the following class "AFHTTPSessionManager.h" in the umbrella header.
I made the umbrella header public in build phases and I also made sure to set Define modules to yes.
However, in my swift framework I am still getting the following error
Use of undeclared type 'AFHTTPSessionManager'
I don't know why this is continuing. I thought swift would automatically pick up my Objective-C import. Any tips or suggestions are appreciated.
I tried following this source
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82
,but it didn't work for me. This is very fusterating.
This is the swift code that causes the error.
import Foundation
class MyApp {
private var manager: AFHTTPSessionManager?
}
The thing is, brigding header doesn't work for Framework targets. Solution is to create module map target to build module map for needed ObjC framework.
Here is example for CommonCrypto: https://stackoverflow.com/a/42852743/1840136; in your case difference should be that script line
header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
will be replaced with path to AFNetworking headers (I'm not sure if you're placing 3rd party libraries just within project or getting from pods, so check by yourself).

Adding unit tests for an existing objective c + swift project

I have an existing iOs project which I would like to add a unit test target to. The classes I'd like to test are both in objective c and swift.
I've managed to create a test target which allows me to test swift only code by adding the implementation swift files to the test target.
However, as soon as I import or use a class that imports objective c code, I run into Linker issues when building the test target:
...
Symbols not found for architecture x86_64
I've tried adding the objectivec mm files to my target which gets my passed the linker error, but I then get an unresolved identifier error for the class I'm importing.
I'm using xcode 9 and swift 3.
edit: I think this may have something to do with the fact the swift bridging header is not available in the test target, however I'm not sure how to add it.
Your test project is a separate target and should have all files it relies upon to be tested linked separately. So first of all click one of the .m files it's missing and check if the test project is also included in the targets. If this is the case there might be a problem with the bridging header your test project uses. Figure out which one it uses from the build settings of your target and see if it includes the same files as your main project.

"Swift is not supported for static libraries" when testing cocoapod

Recently I started creating my pod in Swift. I used pod lib create command and declined offer to use Nimble/Quick as testing library because I hoped to use standard XCTest. However, when I try to run tests, build just fails with message Swift is not supported for static libraries.
I tried to reopen Xcode and clean project, not working.
What should I do in this situation?
Swift don't supported static libraries. If you create lib used objc so you have 2 ways (create static lib and write script for convert to framework) but if you write used swift only one.
So you need create pod. Just create framework in xcode and add files for configurate your project to pod. It't easy, for example you can watch this, I create pod after create project
For swift you need to have Cocoa Touch Framework

iOS 8 extension dependencies issues. Importing one project file to extension view controller

I am working on iOS 8 extension. I read many manuals and all of them just show how simple add extension to your app, and seems that's enough.
But here are many pitfalls:
After adding your extension you will need to import some of your classes to view controller that were created when you added new extension target. The big use here that you will need add all of them and if you have huge project it's not a simple task. Solution can be select extension target then in Build Phases -> Compile Sources press plus button and add all .m files to your target using hot key CMD+A.
After adding all files you can see that some of method wont work, and you can see this error: 'sharedApplication' is unavailable: not available on iOS (App Extension) so the solution can be a macros that check ifndef Extension then we can invoke sharedApplication code.
#import <Foundation/Foundation.h> vs #import <UIKit/UIKit.h>. So I have not figured out with this issue but when I replaced Foundation with UIKit it works for me and all related issues go away.
CocoaPods. All of us are using CocoaPods so if your extension need to use some part of your project code and that code use CocoaPods library then you need to add link_with 'ProjectTarged', 'ExtensionTarget' to Pod file and make pod install again to bind your libraries with new extension target.
So this is a main points I faced with. Maybe someone can suggest how to solve that issue, as I said I just import one needed file to extension view controller. The imported file contain some libraries like AFNetworking, RestKit and other nested classes from the main project. I need this class to invoke few methods with passing data from extension to my backend server. So one file but many issues.
you can use this in your Podfile to prevent "Require only App-Extension-Safe API". Just put it to the end of your Podfile.
post_install do |installer_representation|
installer_representation.project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
end
end
end
1) You only need to add files to the extension target that you actually intend on using. I would recommend only pulling over what you need by finding the files and in the File Inspector, adding them to both targets.
2) Yep that's right. You'll need to update libraries that check that for you or fork them and fix them yourself.
3) I think you're referring to the default templates when creating one of the app extensions. Yes, you need to use UIKit not Foundation. Foundation will work for iOS or OS X, but clearly isn't enough if you are making a UIKit application.
4) The link_with command will make all pods in your Podfile link to all of the targets listed. If that's what you need, then, fine, do that. If you just need a small subset of pods for your extension, use the following:
target 'whateverTarget', :exclusive => true do
pod 'SomePod'
end
To remove sharedApplication issue from CocoaPods Libraries you just need to change Build Options within Build Settings for your pod.
Just type to search Require Only App-Extension-Safe API and then change the value to NO as it is on the image below:
Propably you will need to do this for every of your pods.

How to use a static library (e.g. cocoapods library) on a XCTest?

I'm working with Core Data and, as I the model gets more complex, I need to make sure that the new changes I introduce don't break my model unexpectedly in other parts.
I can create unit tests and run them every time I change something on my model. If something breaks, there might be something wrong with my model or at least I know I have to modify some queries in the main code/tests.
I'm using MagicalRecord to have access to some convenience methods.
I also use cocoapods for the same reason, convenience.
The problem is that cocoapods creates a static library and links it against my target, but in Xcode, new test targets are not automatically configured to link against the same libraries/frameworks the target in question links against to.
How can I have a XCTest link against a static library?
This is not only helpful with MagicalRecord/Core Data, but when you're using an external library it's a good idea to have tests to make sure that updates on the library don't break your App.
If you're using cocoapods, you can simply use link_with to include your test target, but if you're using a static library not created by cocoapods you can do the following:
(I will still use a cocoapods library for the instructions, as that's what I'm working with, but the idea is the same if you're not using a cocoapods library)
Once you have created a new Test Target, click on the project root node in the project navigator and select your test target.
Go to Build Settings and search for Header Search Paths. Double click on the Header Search Paths item and enter
${SRCROOT}/Pods/Headers and select recursive if you want to import all of your cocoapods libraries headers or enter them individually:
${SRCROOT}/Pods/Headers/MagicalRecord leaving non-recursive selected (although in this case it doesn't really matter).
Now search for Linking and in Other Linker Flags add -ObjC
Now with your Test Target still selected, go to Build Phases and in Link Binary With Libraries click on the + and add libPods.a or the other libraries individually (libPods-MagicalRecord.a)
You should be able to run a XCTest using the static library.
Optional: I like to import the headers I know I'm going to use in the -Prefix.pch file. You can go to your target test group in the Project Navigator. Go to the Supporting Files group and open the -Prefix.pch file. For MagicalRecord I like to add:
#define MR_SHORTHAND
#import "CoreData+MagicalRecord.h"
For more information:
Unit Testing with Core Data
Creating a Static Library in iOS
Tutorial
After a lot of fighting, these steps worked for me:
1) Project> Info
On configurations, set the Test Target to share the same Configuration File as your main project (generated by Cocoapods).
Now, you should start to get some errors because XCUnit framework is missing, but now your external libraries imported with CocoaPod are visible on your test project.
2) On the Test Target>Build Settings look for Header Search Paths, once there add:
$(DEVELOPER_DIR)/Platforms/iPhoneOS.platform/Developer/Library/Frameworks
$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks
The Unit Test framework is inside your Xcode App, this headers will make them public to be added later.
3) On the Test Target> Build Phases add the SenTestingKit.framework
And it should look like this
From there, everything seems to work for me. Good Luck.

Resources