Import Xctest into a Dynamic Framework

Creating a framework that uses XCTest

You have to add additional Framework Search Path in the Build Settings:

$(PLATFORM_DIR)/Developer/Library/Frameworks

Cannot load underlying module for XCTest

The main project does not link with the XCUnit framework. You should create a separate testing target for your project, if one does not already exist, and add your test source files to that target.

  1. Select your project in the Project Navigator. This will open the project's settings in the editor.
  2. Click the "+" button at the bottom of the column listing your Targets.

Sample Image


  1. If you are working on an iOS project template, select iOS > Test > iOS Unit Testing Bundle.

    If you are working on an OS X project template, select OS X > Test > OS X Unit Testing Bundle.

Not able to use XCTUnwrap in Test Framework

The XCTUnwrap API is only available in primary test bundle targets and not in other libraries or frameworks. There are two ways to fix this issue:

  1. Move your Optional extension to the main bundle which obviously not something you want to do :)
  2. Modify the following build settings in your test framework target:
SYSTEM_FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PLATFORM_DIR)/Developer/usr/lib",
);
SWIFT_INCLUDE_PATHS = "$(inherited) $(PLATFORM_DIR)/Developer/usr/lib"

Why in iOS Framework, xctest is always red colour?

No, Scheme(not schema) is different from Target. Check out this thread for better understanding Xcode: What is a target and scheme in plain language?

To solve your issue, click on the WSBandKit framework icon on top left section(adjacent to iPad2 simulator icon); and select editScheme option from drop down. You will be presented with a new screen with some option. Go to Build option and tick the option of Run for your test target. Close the screen and Build the framework for Device.
Check the image for reference. Initially the Run option will be unchecked for test target that you have to check. Sample Image

How to reliably install and setup Quick test framework on Xcode 8?

Git submodule way is the most lean and simple way to achieve that.

Follow the these steps to start from zero:

1.a. Create Xcode project with Include Unit Tests checked.

1.b. Alternatively, you could create unit test target on existing project.

  • Open test Navigator.
  • Click the + button in the lower-left corner, then select New Unit Test Target… from the menu:



2. Close the Xcode project in (1)



3. Create new Xcode workspace. File -> New -> Workspace.



4. Open Terminal / Bash Shell / Cmd.exe



5. Create a new sub directory for GitHubProjectClones.

  • for example: $HOME/Developer/GitHubProjectClones



6. cd to sub directory in (5):

  • mkdir Vendor
  • git init



7. Follow step one in Git Submodule section

  • git submodule add git@github.com:Quick/Quick.git Vendor/Quick
  • git submodule add git@github.com:Quick/Nimble.git Vendor/Nimble
  • git submodule update --init --recursive



8. Follow step two in Git Submodule section.

  • Back to Xcode with Workspace open:

    • Make sure Project Navigator is selected

      • File -> Add files to:

        • select the Quick folder created in step 7.
      • File -> Add files to:

        • select the Nimble folder created in step 7.
      • File -> Add files to:

        • select your Xcode project in step 1.



9. Follow step three in Git Submodule section to link Quick.framework and Nimble.framework during your test target's Link Binary with Library build phase.



10. You should be able to follow along the examples in Quick Documentation

Unable to load custom font during XCTest in framework I'm creating

I was able to solve this issue by loading the font file as data and then creating a font using CGFontCreateWithDataProvider. Here is my loadCustomFont method:

func loadCustomFont(name: String, fontExtension: String) -> Bool {
let fileManager = NSFileManager.defaultManager()
let bundleURL = NSBundle(forClass: USDFont.self).bundleURL
do {
let contents = try fileManager.contentsOfDirectoryAtURL(bundleURL, includingPropertiesForKeys: [], options: .SkipsHiddenFiles)
for url in contents {
if url.pathExtension == fontExtension {
let fontData = NSData(contentsOfURL: url)
let provider = CGDataProviderCreateWithCFData(fontData)
if let font = CGFontCreateWithDataProvider(provider) {
CTFontManagerRegisterGraphicsFont(font, nil)
}
}
}
} catch {
print("error: \(error)")
}
return true
}

Once I loaded fonts this way (instead of the usual Info.plist way), I was able to load the font during the XCTest.

iOS Framework Tests fail in Xcode Workspace

After looking at the issue again, I could find the reason for the strange behaviour.

Short Answer:
There is a private OAuth Apple Framework located at /System/Library/PrivateFrameworks/OAuth.framework/OAuth which causes a name clash with my own OAuth framework because xctest seems to link this framework.

Long Answer:
xctest or XCTest.framework seem to load an OAuth.framework from the Private Frameworks folder.

If one uses a workspace within Xcode, the test environment uses the following environment variable for dyld:

"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;

The variable has the following effects:

DYLD_FRAMEWORK_PATH
This is a colon separated list of directories that contain frameworks. The dynamic linker
searches these directories before it searches for the framework by its install name. It
allows you to test new versions of existing frameworks. (A framework is a library install name
that ends in the form XXX.framework/Versions/YYY/XXX or XXX.framework/XXX, where XXX and YYY
are any name.)

For each framework that a program uses, the dynamic linker looks for the framework in each
directory in DYLD_FRAMEWORK_PATH in turn. If it looks in all the directories and can't find
the framework, it searches the directories in DYLD_LIBRARY_PATH in turn. If it still can't
find the framework, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALL-BACK_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH
BACK_LIBRARY_PATH in turn.

DYLD_FRAMEWORK_PATH defines the search directories for Frameworks and overrides the default search paths and the install names, which embedded into the depending binary. Even if a binary specifies a framework install path like
/System/Library/Frameworks/OAuth
the environment variable leads to the behaviour that the directory
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator
is searched for an ​OAuth.framework/OAuth binary regardless of the actual install name.

This behaviour is intended since it allows for overriding Frameworks in an existing binary with newer versions without the need to recompile the binary.

However, it can also entail misleading linking of binaries if two Frameworks have to same names. Then, one of the Frameworks with the same name could be loaded even if the other one is specified by path. If the directory of the first one is contained in the DYLD_FRAMEWORK_PATH either prior to the other one’s directory or at all, then the first one is picked because of its name and regardless of the specified install name path.

Concrete Example:

xctest binary load command:
​/System/Library/PrivateFrameworks/OAuth.framework/OAuth (compatibility version 300.0.0, current version 1280.24.0)

OAuth is present at the following paths:

/System/Library/PrivateFrameworks/OAuth.framework/OAuth
/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth

xctest is started with the following environment variable:

"DYLD_FRAMEWORK_PATH“ = "/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks“;

Then the OAuth Framework at

/Users/{USER}/Library/Developer/Xcode/DerivedData/{PROJECT}/Build/Products/Debug-iphonesimulator/OAuth.framework/OAuth
is used even if the install name is

/System/Library/PrivateFrameworks/OAuth.framework/OAuth



Related Topics



Leave a reply



Submit