Starting with an app already in development, I have carried out the instructions in the iPhone Development Guide – Unit Testing Applications
I can successfully include and use my App's classes in Application-style tests that run on the device, and output their results to the console.
If I add the following line of code:
STAssertTrue([viewController isKindOfClass:[LoginViewController class]], #"Top view controller is not LoginViewController");
The following build error is generated:
Undefined symbols:
"_OBJC_CLASS_$_LoginViewController", referenced from:
__objc_classrefs__DATA#0 in LoginViewTest.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
I can provide more configuration information for the project and the Testing target, but the setup works file without the [LoginViewController class] line in the test source.
Without that line, I can reference the class, use it's properties and send it messages successfully.
Is there a linking build setting, or bundle loading option that is required when attempting to use an App class in this fashion? Or should I find another type of test to confirm that the class of an object is the expected one?
I have found an answer, but I think there must be a "better" way?
In the build configuration for the Unit Tests bundle, you can specify the Bundle Loader (BUNDLE_LOADER) setting that points to your "host" App.
${TARGET_BUILD_DIR}/AppName.app/AppName
The Unit Tests bundle is being built as a dependency of your App's unit testing target (say, AppName Testing), and as a result I haven't been able to resolve the App executable any better than the above.
The net result is a working unit test injected into the Testing target without any linker errors. The tests run and access the classes as expected.
EDIT: Bundle Loader – Target Configuration
It's important to configure the target that is "hosting" the testing bundle to not hide it's symbols.
GCC_SYMBOLS_PRIVATE_EXTERN = NO
a.k.a. "Symbols hidden by default". From the documentation:
When enabled, all symbols are declared
'private extern' unless explicitly
marked to be exported using
'__attribute__((visibility("default")))' in code. If not enabled, all symbols
are exported unless explicitly marked
as 'private extern'.
For more information, see
http://developer.apple.com/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html.
I just answered this over here:
iPhone unit testing: Symbols not found when calling custom code
I suppose one of these should be closed as a duplicate? I'm not reputable enough to do so...
I also followed Apple's iPhone Unit Testing Applications document and saw a linking error similar to the one described in the question when trying to unit test one of my classes.
Looks like any class referenced in your unit test class and so being run from your test target also needs to be added to that test target. To do this, you would right click your RootViewController class and click 'Get Info' (Cmd-i shortcut). On the targets pane, make sure your unit test target (e.g. 'LogicTests', if you've followed the naming in that document) is checked.
Now that class will be compiled with your tests and should be available to your unit test. To double check, expand the 'Targets/LogicTests/Compile Resources' node in the 'Groups & Files' browser on the left. This lists all the class files available when building the target and should now include your unit test class together with your class under test.
(Note that you'll need to similarly select all appropriate targets when you create a new application or test class - on the same page of the 'New File...' window when you name the file).
(I'm using XCode 3.2.3 & OS 4.0, by the way).
Related
I have started a small collection of helper code in a Swift Package for my own needs. If i include this package in my main project using Swift Package Manger and try to build it using Xcode Cloud, i get the following error:
ITMS-90334: Invalid Code Signature Identifier - The identifier
'AppulizeStandardTools-55554944b34e30d285943c0fa8b9aecb5744a53e'
in your code signature for 'AppulizeStandardTools_BFA0AAD86B154A1_PackageProduct'
must match its Bundle Identifier 'AppulizeStandardTools'
I haven't set any identifiers or code signing manually with regards to the package and the Package.swift is very simple.
What am i doing wrong here?
I lost half a day trying to figure this out, documentation is not plentiful on it atm.
It appears to be related to how XCode Cloud handles the signing for dynamically embedded frameworks... Not ideal if you are using a microcomponent architectural pattern.
Fix for this:
Go into your main target (executable) -> Frameworks, Libraries and Embedded Content section -> Change your frameworks to:
Embed & Sign => Do Not Embed
Go to Build Settings for each Framework and change the Mach-O Type from Dynamic to Static
There are some implications about how this would effect device memory, I found it to be pretty negligible in my case.
For example, I never use the description of XCTestCase.expectation, so I'd like to use a function to provide a default for it, and make it clear via naming that I'm initializing the expectation, as you can't really use an initializer for XCTestExpectation. But if the extension is not in a test target, then it can't compile:
Cannot load underlying module for 'XCTest'
import XCTest
public extension XCTestCase {
func makeExpectation() -> XCTestExpectation {
return expectation(withDescription: "")
}
}
I've created an xcworkspace here (https://github.com/dtweston/TestFrameworkSample) that demonstrates a solution to your issue. There are two projects in this workspace:
SampleApp project with an iOS app target and a unit test target.
SharedTestFramework project that imports XCTest and declares the single extension you put in your question.
The SampleAppTests target links to the SharedTestFramework to be able to use the extension it defines. The single test file imports the SharedTestFramework.
With those steps, I also encounter the Cannot load underlying module for 'XCTest' when building the SharedTestFramework.
The fix for that is to update the Framework Search Paths to include "$(PLATFORM_DIR)/Developer/Library/Frameworks". Now the SharedTestFramework compiles correctly, and as you can see in the workspace I uploaded, the SampleAppTests target is able to use it successfully.
Old and busted answer
Are you building a separate framework that is designed to be imported into test targets? If that's the case then I think you just need to reference XCTest.framework from this custom framework you're building.
On the other hand, if you're trying to add this extension to a framework that is used by your app target, that seems like a bad idea, because it would mean linking XCTest.framework to the binary that goes to the store and runs on people's devices.
I'm not sure if that's possible. I'm more confident that it's not a scenario Apple expects or supports.
I am being presented with a very interesting project. The task that I must complete is to figure out a way to allow a partner to be involved in an app without giving up their source code. The code will be included in the main bundle of the app so it is not dynamically stored. The partner has a fully functional app that is needed to be ran in a window within the main app at the appropriate time. I know having the partners create a web app would be ideal so it is treated like a webpage but I am more concerned with codes that must be written natively in iOS.
My question is what is the best way to go about solving this? In theory it is like an App within an App. Is there a way if they gave up their .app file I can include this in the bundle and then run it when I catch a certain event? Should I have the partners create their code in a framework and then import into the shell project? What is the best way to approach this problem?
If your 2nd-party doesn't want to provide you with the source code, why doesn't he compile it to object code then let you simply link it to your app?
By the way, at least on official (non-jailbroken) iDevices, apps can't 'embed' or 'open' one another in such a way - you can open an app programmatically if 1. it's a separate app 2. it has a registered special URL associated to its bundle.
Is there a way if they gave up their .app file I can include this in
the bundle and then run it when I catch a certain event?
No, you'll want to have them create a library instead. You can then include that library in your project.
Creating a library is as simple as:
Choose File->New...->Project... in Xcode.
Select the "Cocoa Touch Static Library" project template.
Add your code.
Build.
The result is a static library that you can add to your application(s). The library will contain the compiled code that you added, but doesn't include the source code. The library developer should provide whatever header files are necessary to use the code in the library.
An App within an App is possible however it requires a common data framework that allows one app to reference the same data without confusing the the source of and destination of the data.
Such a framework allows one app to interact with another app referencing the same data.
I have an app that works with and without the linker flag. However, without the linker flag, I get a very different behaviour when adding data to a view.
This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.
From this Technical Q&A
My colleague and I have been struggling with unit tests now for weeks. We have tried to get SenTest, GTM, and other frameworks set up, but we can never get past a gnarly ball of linking errors.
Here's where I am now with GTM. I would appreciate any guidance.
Beyond helping out on SO, if you have experience with this, I'd happily pay a consultant. Please email me at andrew#gaiagps.com if you think you can help me with this.
I followed the instructions here:
http://code.google.com/p/google-toolbox-for-mac/wiki/iPhoneUnitTesting. I found I also needed to add the file "GTMObjC2Runtime.h" to the project. Then, I was able to get to the point where I got the expected console output after installing the framework: "Executed 0 tests, with 0 failures (0 unexpected) in 0.030 (0.030) seconds"
Next, I went to write a test case for one of my classes. I created WebAPITest.h. I created a simple test, which worked fine. I just verified 1 == 1.
Next, I decided to write a test for my AppDelegate.h. So, I added #import "AppDelegate.h" to WebAPITest.h, and I got 8 linking errors. My project uses FBConnect, and the compiler complain that it can't find the FBConnect files. To address this, I added the the FBConnect header search path to the Test target's build config, and the linking errors went away.
Now is where I am stumped. When I try and reference AppDelegate in the implementation, I get these linking errors:
Building target “fooTest” of project “foo” with configuration “Debug” — (2 errors)
Undefined symbols:
".objc_class_name_AppDelegate", referenced from:
literal-pointer#__OBJC#__cls_refs#AppDelegate in WebAPITest.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
So, I tried adding AppDelegate to the Test target, but then it
started wanting all the dependencies for AppDelegate too, and I'm
guessing I'm not supposed to add dozens of files to the unit test
target.
Any idea what I need to do next?
Your test bundle does need access to the compiled class you are trying to test. It's your decision to accomplish that by either adding it directly to the target (and yes, with all its dependencies), by linking to a library that implements the class, or by setting up your test bundle so that it is loaded by a host application that has an implementation of the class.
This reference might be useful to you:
http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html#//apple_ref/doc/uid/TP40007959-CH20-SW3
And also from the main unit testing documentation at Apple:
http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/UnitTesting/1-Articles/CreatingTests.html#//apple_ref/doc/uid/TP40002171
Look for terms like "Test Host" and "Bundle Loader."
This stuff is not very straightforward to understand but the documentation eventually clarifies everything if you hunker down and plow through it.