#testable import of Watch Extension module in Swift unit tests - xcode

I've noticed recently that #testable import doesn't seem to work for Watch Extension modules.
Here's what I've tried so far:
Create a new Xcode project with WatchKit app and include unit tests.
Open the auto created unit tests file and add #testable import ProjectName_WatchKit_Extension (after confirming that this is the correct module name in the extension's build settings). This gives a 'no such module' compiler error.
Confirm that 'Enable testability' is set to yes in Extension build settings.
Change name of Extension module to remove spaces
I am of course able to successfully unit test by adding the required files to the test target, but it feels like this should not be necessary.
Has anyone been able to successfully use #testable import with a Watch Extension? Is this something I should be able to do? Any help would be much appreciated.

From an Instagram library IGInterfaceDataTable: https://github.com/facebookarchive/IGInterfaceDataTable/tree/e5565a96c5a71ef7b849920adc34f880cc37dc03#testing
Since WKInterfaceTable objects must be initialized from storyboards, and
there is no mechanism yet to create a WatchKit storyboard in code, we cannot use
Xcode unit tests yet.
For now, tests are run manually by executing the ApplicationTests WatchKit
extension and ensuring that none of the asserts are fired.
This is a good question, I saw a similar issue was opened against Quick and Nimble testing framework which talks about the lack of support for watch kit extension testing. Take a look: https://github.com/Quick/Quick/issues/273.

Related

Importing 3rd party framework in a Playground's "SupportCode.swift"

Is there a way to include a (non-Apple) framework in the "SupportCode.swift" file, in the Sources directory of a Playground?
While the framework is successfully imported when the import directive is placed in the Playground itself, I get a "No such module" error popping up when trying to import the same framework in SupportCode.swift.
I have my playground embedded in a workplace with the required frameworks added to it as well.
It is a hack. if you have file like "Parse.framework", just copy it to Xcode's system frameworks folder at "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks"
Now you can import this framework in playground just like any other system framework.
This didn't work until recently.
In order to import an external framework, you have to have the playground and your framework's target/project in an Xcode Workspace. Once you have that and you build the framework, you can just import the framework with an import.
If the playground is already in a project that is not a workspace file, you can convert the project to a workspace by choosing File > Save As Workspace then add the playground to that workspace.
You can also drag the framework project in the Finder to the project navigator in the workspace.
Open the playground file in the editor, and add import the custom framework using an import statement.
NOTE: These are the conditions.
The framework is in the same workspace as the playground.
The framework has already been built.
If it is an iOS framework, it is built for a 64-bit run-time
destination.
The workspace contains at least one active scheme that builds a
target.
If it is an Objective-C framework, it sets the Defines Module build
setting to Yes.
I have found this tutorial exactly how I was doing in my project.
https://m.pardel.net/using-3rd-party-frameworks-in-swift-playgrounds-fd415f6dba10
Please don't miss to add empty .swift file in your project as describe in this answer https://stackoverflow.com/a/47922876/855261

Writing XCTestCase for Mac OS Command Line Tool

I am trying to unit test a command line tool written for Mac OS.
When I first create the project, XCode does not generate a tests group in the project navigator. When I try to add a new test target, it doesn't give me the option to specify my target as the "Target to be Tested".
My question is this: is it even possible to use XCTest for a Command Line Tool project? Or is it just considered trivial to do so by virtue of the fact that I could just run it from the command line? I could understand that reasoning, but there is internal functionality I'd really like to test.
I'm not sure what version of Xcode you are using, but I ran into a similar problem using the templates in Xcode Version 6.2 (6C131e). That said, I was able to get XCTests to work with a Command Line Tool project. The solution was to ignore the "Target to be Tested" field during creation and instead add the Test target to the main scheme after creating it:
Go to Manage Schemes. You should see your main Target’s scheme and a
newly created test scheme.
Select you main scheme and go to Edit.
Select the Test action and add your new Test target to the tests
list using the “+” in the Test action detail panel.
From there you should be able to run the tests using cmd-U.
In Xcode 8.2, I was only able to run unit tests in a command line app by adding a unit test target from the Test Navigator, then editing the testing scheme to include that new test target under the "tests" list, and manually adding testable source files to the test target from the "target membership" section of the File Inspector pane.
(Adding a unit test target from the project "add target" screen wouldn't link properly with XCTest framework, even after adding the framework to build phases.)
Following the Apple doc directions for adding a unit test target from the Test Navigator pane looks like this:
Note:
In the Unit Test Target setup, the "target to be tested" dropdown still won't select the command line tool. Leave this option as "None".
For adding unit test target (XCTest) for Mac OS Command Line project which has(main.swift and other swift files), to make this work,
1.Add UnitTests target to scheme by editing in manage schemes
2.Make your functions and classes has PUBLIC access
This solved my linking errors. Hope it helps for you guys as well

Unit tests failing without any message if linked to a custom framework

Update (From Build log):
"The bundle “Lib2Tests” couldn’t be loaded because it is damaged or missing necessary resources."
(dlopen_preflight(/Users/abc/Library/Developer/Xcode/DerivedData/Lib2-gaplfrtqethacsgkmjmlivcyuity/Build/Products/Debug-iphonesimulator/Lib2Tests.xctest/Lib2Tests):
Library not loaded: #rpath/Lib1.framework/Lib1
It seems the lib2.framework project only linked the Lib1.framework and it didn't embed it, and there's no option to embed the framework inside another cocoa touch framework, that's why at the end unit test failed as it couldn't find the referenced Lib1.framework.
put simply if FrameworkB is dependent on FrameworkA for some functionality down the road, UnitTests of FrameworkB will cease to run - if FrameworkA is linked to FrameworkB
Setup
I've created a simple isolated case to demonstrate and reproduce the problem.
I've 2 Swift Cocoa Touch Frameworks (Lib1 & Lib2 - Lib2 is dependent on Lib1 - single swift file with single unit test in each)
Lib2 unit tests will only work if you remove the linked Lib1. Interestingly both projects works on their own if run independently.
Question: is this a bug in Xcode? any workarounds?
Smallest Reproducible Example Project: https://www.dropbox.com/s/kycnvt1qvz8zw4o/LibTest.zip?dl=0
I'm attaching a screenshot, it's weird, no error messages or failure details in the console, all I get is a notification on the side the unit test failed. The test is not complicated, single line instantiating a class and it's runs successfully if I remove the link to my custom framework. (the custom framework itself also simple and runs/tests successfully on it's own) To observer this behavior simply delete the linked framework from the project files and run "Test" again. I believe the error is related to project files settings etc. and the solution requires to look into project file itself.

Do I have to do something to get OCunit tests to compile out of box with XCode 4?

I just installed XCode 4 today (using Apple mac app store), and I created a new Mac OS application, and tried to switch to test mode,and build the test skeleton code it generated for me. It failed here:
In mytests.h:
#import <SenTestingKit/SenTestingKit.h>
The error is:
file://..mytests.h: error: Lexical or Preprocessor Issue: 'SenTestingKit/SenTestingKit.h' file not found
Now, when I use locate from the terminal to find SenTestingKit.h, I notice it exists under the /Developer-old/Library/Frameworks folder (which is what XCode 4 installer renamed my /Developer folder to). There is no new /Developer/Library/Frameworks. And I can't seem to find SenTestingKit.framework on my disk, other than the developer-old one.
What's up? It seems SenTestingKit.framework is not shipped with XCode 4.
Update:
Furthermore, When I copy my old SenTestingKit framework from XCode 3 into /Developer/Library/Frameworks, it sort of builds, but it doesn't work the way I would expect. The dummy test is designed to just fail, but when I "run test", I just get the normal cocoa app document window opening, and no indication that my test has failed (as I intend it to do).
This is pretty bad. I can't get a Unit test to FAIL. That's not the usual situation for me, you understand.
You may find that the reason for this is because you've installed Xcode 4 into a directory such as /Xcode 4.x/ or similar. The space is causing the problem because the -I paths are "Xcode" and "4.x/Library/Frameworks".
To fix this, what you need to do is select your test target, and under its build settings go and find the Framework Search Path, and put quotes around the two arguments, so you have:
"$(SDKROOT)/Developer/Library/Frameworks" and "$(DEVELOPER_LIBRARY_DIR)/Frameworks"
Then you default tests will compile, link and fail.
You will maybe need to import the framework into your project. Otherwise, the header file won't be recognize.
If you can't see the framework you're looking for, you can adjust the framework look paths in your project's build settings.
When you're building unit tests in the same project as you main code, make sure that XCode 4 didn't automatically connect you mytests.m file into the "Compile Sources" section of your main code.
For example, if you have two targets in our project:
MyProject
MyProjectTests
Check the Build Phases for MyProject to see if XCode added mytests.m into the "Compile Sources" accordion. This will cause your builds to fail because SenTest isn't included in the main project.

Xcode 3.1.3 problems unit-testing a plug-in

Following Chris Hanson's blogs and Apple's Automated Unit Testing with Xcode 3 and Objective-C I have started implementing unit tests for my projects. However, I use a lot of plug-ins (loadable bundles) and I can't quite figure out how to test them.
I figured I would use the approach Chris Hanson described for testing frameworks.
I started with a Cocoa Bundle project, added a principal class and changed the type to plugin.
Then I added the unit test bundle, add the plugin as a direct dependency (Apple's instructions) and set the following build settings:
Bundle Loader: $(BUILT_PRODUCTS_DIR)/CocoaPlugin.plugin/Contents/MacOS/CocoaPlugin
Test Host: $(BUNDLE_LOADER)
The problem is that as soon as I've done that and build the test target, I get this message:
error: Test host '/Users/elisevanlooij/Documents/Plug-ins/CocoaPlugin/build/DebugCocoaPlugin.plugin/Contents/MacOS/CocoaPlugin' exited abnormally with code 127 (it may have crashed). [code 126 in another plugin]
I had hoped that adding the otest custom executable would help, but unfortunately not. I really hope someone can help because not being able to unit test my plugin really puts a cramp in my testing lifestyle.
Take a step back. Your Bundle Loader setting is erroneous and adding a custom executable is not going to affect compilation of a unit-test bundle.
You need to get your unit-test bundle to build without errors (and warnings!), and your tests will run automatically (you do have at least one valid SenTestCase class with at least one valid test method, right?).
So,
are you saying that your test-bundle compiles without warnings and you have written some tests using classes and methods from your plugin? If so you must have some how taken care of loading the plugin-bundle into the unit-test-bundle and defining some kind of API, as the plugin-bundle doesn't have any public headers, right?
see Apple docs here
Loading plugins into plugins (essentially what you are trying to do) is not easy and they are not magically 'linked' at compile time like the frameworks in the Chris Hanson Blog that you refer too. They wouldn't be plugins if they were.
The simplest way to go is to not actually test your plugin at all but add the files you want to test directly to the unit-test bundle. At least this way you can get on with testing your code without fiddling about with dynamically loading bundles.
But if this isn't satisfactory, you can get what you are trying to do to work with a little effort - you should definitely add tests to verify that your plugin is loaded and that the symbols you think are available REALLY are available. Once your tests build ok you should follow Chris Hanson's other excellent blog on debugging unit test bundles showing you how to step thru your tests in the debugger - you should be able to track down any errors.
Your
Bundle Loader: $(BUILT_PRODUCTS_DIR)/CocoaPlugin.plugin/Contents/MacOS/CocoaPlugin
is correct. It means that when
linking your test bundle you do not include the classes under test there, and they will
be looked up from CocoaPlugin. It is a compile time setting and should cause your test
bundle to compile/link sucesfully. (See -bundle_loader in man ld)
Your
Test Host: $(BUNDLE_LOADER)
is incorrect. Your test host should be either an application (with a NSApplicationMain called from main method) or not set. This TEST_HOST setting is a runtime setting to run your unit tests. You basically have two options:
Do not set TEST_HOST, and load your plugin from your test bundle. For example you can do this using the initlaize method.
Create a dummy test_host application that will load your plugin, and then call NSApplicationMain, and use this app as your TEST_HOST.
The +initalize method for your test bundle to load the plugin would look like this:
+ (void)initialize
{
NSBundle* bundle = [NSBundle bundleWithPath:pathToPlugin];
[bundle load];
NSLog(#"Loaded:%#\n",bundle);
}
The main method in your dummy_test host app can look like this:
int main(int argc,const char** argv)
{
NSBundle* bundle = [NSBundle bundleWithPath:pathToPlugin];
[bundle load];
NSLog(#"Loaded:%#\n",bundle);
return NSApplicationMain(argc,argv);
}
Other ideas for testing plugins:
use an independent bundle: Do not specify either BUNDLE_LOADER or TEST_HOST and put your classes from the plugin also into the unittest bundle.
put your test cases into the plugin, and try to get that unittest. Just weak link SenTestingKit to your plugin and add a script phase with: TEST_RIG=/Developer/Tools/otest "${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests".

Resources