I am searching for a way to separate the UI tests from the original repository where the main app stays. Is it possible to have the UI test code in another repository, "reference" the main app in some way, and test it?
Starting in Xcode 9, this is possible as long as you're willing to give up a few features. After creating a UI test bundle, you can go to the target settings to specify that it has no target application. (You may also be able to create a UI test bundle without specifying one to begin with.) After you've removed the target application, rather than using the default initializer for XCUIApplication, you can use the initializer that accepts a bundle identifier.
Your tests will end up looking something like the following:
var app: XCUIApplication {
return XCUIApplication(bundleIdentifier: "com.yourdomain.product")
}
func setup() {
app.launch()
}
func test() {
app.navigationBar.buttons["Add"].tap()
}
If you go this route, you will lose the ability to use a few features. Namely:
You won't be able to use Xcode's built in test recorder. The record button is disabled unless you have a target application configured. That being said, you could create an empty app in your project and just switch to the application you'd like to record instead. (That being said, I haven't found Xcode's record feature to be very useful, even for single project apps.)
Xcode won't automatically install your application for you. That usually isn't an issue since is located in a different repository (and sometimes isn't even an Xcode project), so you'll just need to install it before starting your tests. The iOS simulator allows you to drag and drop a .app file, so installing the app is easy enough.
This function fails with runtime error:
-[UIWindow viewForFirstBaselineLayout]: unrecognized selector sent to instance 0x7fb9dae257d0
Anybody encountered the same?
UPD:
Fails on simulator iOS 8.1/8.4. 9.3 works fine.
UPD2:
UIWindow is created like:
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = RootViewController.rootVC
window?.makeKeyAndVisible()
I got the view debugger working again by placing the following fix in my project:
#ifdef DEBUG
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#implementation UIView (FixViewDebugging)
+ (void)load
{
Method original = class_getInstanceMethod(self, #selector(viewForBaselineLayout));
class_addMethod(self, #selector(viewForFirstBaselineLayout), method_getImplementation(original), method_getTypeEncoding(original));
class_addMethod(self, #selector(viewForLastBaselineLayout), method_getImplementation(original), method_getTypeEncoding(original));
}
#end
#endif
When your project loads, the load method will execute, causing viewForFirstBaselineLayout and viewForLastBaselineLayout to use the viewForBaselineLayout implementation if they are not currently implemented, so view debugging gets iOS8 flavor the behavior it was looking for.
To add this to your own project, create a new empty Objective-C file in your project and paste the contents in. You can name it whatever you want. I call mine "UIView+FixViewDebugging". If you are in a pure Swift project you do not need to create a bridging header. The file will be compiled into your project and you don't need to reference it.
Note this will only work for debug builds because of the #ifdef DEBUG. You can remove it but then you may accidentally compile this into your release builds (though it should have no ill side effects). If this method isn't working with these lines, check that your target has DEBUG=1 in Build Settings > Apple LLVM - Preprocessing > Preprocessor Macros > Debug.
Looks like Xcode 7.3 uses viewForFirstBaselineLayout property to draw the UI. But this property is marked as available since iOS 9.0.
[UIView viewForFirstBaselineLayout] method should be used for the version prior to iOS 9.0. It seems the guys from Apple didn't consider this case.
Yes. when click the debug view hierarchy button ,the page has nothing, and print "[UIWindow viewForFirstBaselineLayout]: unrecognized selector sent to instance 0x7fb9dae257d0" .
To solved it, just be sure you are using the iOS systom not below iOS 9.0 and you will still use that function freely.
I have a type in my module:
import Cocoa
class ColoredDotView : NSView {
...
}
It is used in a number of different classes with no issue:
class EditSubjectPopoverController : NSObject {
#IBOutlet internal var subjectColorDotView : ColoredDotView!
...
}
But for some reason, when I use it in one specific class, I have compilation errors on the type:
class EditTaskPopoverController : NSObject {
#IBOutlet internal var lowPriorityDotView : ColoredDotView! // Error here
#IBOutlet internal var medPriorityDotView : ColoredDotView! // And here...
#IBOutlet internal var highPriorityDotView : ColoredDotView! // And here...
...
}
The compilation error is:
EditTaskPopoverController.swift:15:49: Use of undeclared type
'ColoredDotView'
Which I don't understand. It's the first compilation error in the file, and the rest of the errors are all symptomatic of the first. Further, there are no other files with compilation errors. I don't understand why the type is undeclared, as the file is in the same module:
I have tried cleaning the project, cleaning the build folder, and restarting Xcode, to no avail. What potential missteps can cause an undeclared type compiler error in Swift?
For me, I encountered this error when my test target did not have some swift files that my app build target had in compile sources. It was very confusing because the 'undeclared type' was being used in so many other places with no problem, and the error seemed vague. So solution there was of course to add the file containing the 'undeclared type' to the test target.
This has already been answered by #Craig Otis, but the issue is caused when the classes in question do not belong to the same targets, usually the test target is missing. Just make sure the following check boxes are ticked.
Edit
To see the target membership. Select your file then open the file inspector (⌥ + ⌘ + 1) [option] + [command] + 1
Phew, finally diagnosed this. Somehow, the offending Swift file EditTaskPopoverController.swift was in two different build phases.
It was in Compile Sources properly, with all the other Swift files, but it was also, for some very strange reason, in the Copy Bundle Resources phase as well, along with all my XIB and image resources.
I have no idea how it got there, but removing it from the extra build phase resolved the issue.
In XCode menu Product->Clean and then Product->Build worked for me. I encountered this issue when added new ViewController to my project in new Group/Folder.
I had the exact same problem. Some of the files in my framework were not reachable from other classes within the same module.
For some reason the files that had been added to the framework in Xcode was not part of the Compile Sources. If your Swift file is not part of the compile sources you need to add them by tapping the + and selecting them in the popup.
Also make sure the file is part of the framework target. (The little box in the screenshot below should be checked)
The cause for me was a function name that began with same characters as a type:
#IBOutlet weak var tableView: CustomTableView!
and in the implementation I had a function beginning with CustomTableView
func CustomTableView(tableView: CustomTableView, dataForRow row: Int) -> NSData {...}
The fix was to change the function signature so that it didn't begin with the same characters as the type (CustomTableView), e.g.:
func dataForRow(row: Int, tableView: CustomTableView) -> NSData {...}
This was a very misleading error message for the actual cause in my case.
In case anyone encounters a similar problem but the Compile Sources fix does not solve the problem, restarting Xcode may (it worked for me). My version of Xcode is Version 6.1 (6A1052d).
Sometimes errors can be very silly
Before checking all the solutions up here , make sure you have
imported all the basic stuff
import Foundation
import UIKit
It is quite a possibility that when you import some files from outside
to your project, which may miss this basic things as I experienced
once .
In my app I have app delegate and other classes that need to be accessed by the tests as public. As outlined here, I then import my my app into my tests.
When I recently created two new classes ,their test targets were both the main and testing parts. Removing them from their membership from the tests solved the issue.
In my case, the TestTarget's compile sources were having files from the Main Target.
Ref:
Why this happens ?
This happens since we check the TestTarget association while creating
the file
Or manually checking this option from the inspector.
Ref:
How did i resolve ?
I removed the main target's files from compile source of Test Target
I tried many of the solutions offered here, but eventually deleted the file and created it again, and Xcode was mollified :/
This can also happen if you by accident capitalize the parameter name, and call it the same as the object.
class func didRecieveData(BlockItems: [BlockItems])
This might help someone.
I've created new test project with Core Data called "CoreData". Shortly I've got "Use of undeclared type" for NSManagedObjectContext and other Core Data classes. After several attempts of importing, adding to Build phases, etc. I've deleted project and started new one called "TestingCoreData" and it all worked well.
Don't name (test) Projects like name of the Classes
This can also happen if you have a function with the same name as an object type in your signature. For example:
class func Player(playerObj: Player)
will cause the compiler to get confused (and rightfully so) since the compiler will first look locally within the file before looking at other files. So it looks at "Player" in the signature and thinks, that's not an object in this scope, but a function, so something is wrong.
Perhaps this is a good reason why I shouldn't capitalize class functions. :)
I got this error message in Xcode 8 while refactoring code in to a framework, it comes out that I forgot to declare the class in the framework as public
Maybe you have added class with some "FirstNameClass" and after that manually rename to "ColoredDotView". Try to copy content of "ColoredDotView" class to clipboard, remove "ColoredDotView" from project and add agin.
This id fix similar problem from me.
In my case was a mistake made by me. I added a new file as "OS X>Source>Cocoa Class", instead of "iOS>Source>Cocoa Touch Class".
In my case, this was caused by a subclass name being used in the very next line as a variable name with a different type:
var binGlow: pipGlow = pipGlow(style: "Bin")
var pipGlow: PipGlowSprite = PipGlowSprite()
Notice that in line 1, pipGlow is the name of the subclass (of SKShapeNode), but in line two, I was using pipGlow as a variable name. This was not only bad coding style, but apparently an outright no-no as well! Once I change the second line to:
var binGlow: pipGlow = pipGlow(style: "Bin")
var pipGlowSprite: PipGlowSprite = PipGlowSprite()
I no longer received the error. I hope this helps someone!
When testing Swift code that belongs to the application, first make sure the test target is building the application as a dependency. Then, in your test, import the application as a module. For example:
#testable import MyApplication
This will make the Swift objects that are part of the application available to the test.
In my case, that was caused by swift files's Text Encoding.
One file showed 'No Explicit Encoding', and after convert that to 'UTF-8', problem solved.
And the reason why file's text encoding is not explicit is that I copied all code from other swift file.
No Explicit Encoding Screenshot
UTF-8 Screenshot
Cleaning the project solved my problem.
Steps:
Product -> Clean(or Shift + Cmd + K)
In my case I wanted to add a method with a custom swift object as a type parameter, and the name I gave to the variable in the parameter was exactly the same as the custom object class name
The problems was something like this:
func moveBlob(**blob** : blob){
...code
}
The part in bold characters was causing the error of undeclared type
as others mentioned well and in this thread
use of unneeded swift files in "copy bundle resources"
Like others, it was some unrelated code that was causing the #testable to malfunction.
In my test target there was an Objective-C header file that had
#import ModuleUnderTest;
I removed this line (because the import was actually unnecessary) and miraculously #testable starting working again.
I was only able to track this down but removing everything from my project and adding it back in bit by bit until it failed. Eventually I found the problem line of code.
if you are accessing it from different module or Target then you just need it to public it
In case someone makes the same silly mistake I did...
I was getting this error because in renaming my source file, I accidentally removed the. from the filename and so the compiler treated the file as a plain text file and not as source to compile.
so I meant to rename the file to
MyProtocol.swift
but accidently named it
MyProtocolswift
It's a simple mistake, but it was not readily obvious that this is what was going on.
Not adding the correct import delcaration can also be an obvious miss. For me, I had simply omitted to import PriorityUIKit.
My situation is that I drag a new file XXView.swift into the project. And declare a View type to be XXView then the error "use of undeclared type....".
I just try to add my XXView.swift to the test target which it solved the error.
But I didn't want my UI Class involved in the test target.
Finally, I found my ViewController already in the test target which should not happen. ( I think because I create the VC by an xctemplate therefore, it automatically be included in the test target)
I remove the view controller from the test target, and then my XXView is now no need to add to the test target.
Conclusion: make sure all your related files should also uncheck the test target.
After spending an hour on this error I found that the module file is duplicated. delete the extra file, and shift+cmd+k to clean and the error is gone.
In my case, the issue was with a new class not being recognized. I solved the issue by deleting the class and re-adding it but this time checking the Watch App Extension option when creating the new class.
Please note that I do have a Watch App Extension in my Application.
When I run my tests in XCode 5, the main window of my OS X app appears on the screen for a couple of seconds while running the tests. Why? Even if I uncomment all my tests it still opens my main window.
You are running application test, not logic test. This means an instance of your app will be started and then run the unit tests. This allow you to perform some integration test that require your app is running.
Here is the guide to setup application test and logic test.
If you want to change it to logic test (so it run faster and don't need to start your app first):
go to build settings for your unit test target
search Bundle
remove Bundle Loader and Test Host
Thats right, you have to delete the "Bundle Loader" and "Test Host" from your build settings.
But you have to add the necessary implementation files to your unit test target. The necessary files are what you want to use in your unit test cases. You need to do this because in logic tests XCode wont compile the whole application. So some of your files will be missing.
This is en error message if you have left out a file:
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_Module", referenced from:
objc-class-ref in Lobic Network.o
objc-class-ref in Logic_Unit.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You can add the missing files by selecting the implementation file and bringing up the file inspector. There will be a section named "Target Membership" and there you can set the files target membership to your unit test also.
With XCTest, application files DO NOT need to be included within XCTest targets. The XCTest bundle is linked against the application which makes those files available during runtime.
To make this work, ensure the compiler option "Symbols hidden by default" is set to NO Within the Application target.
Here is a blog post with screenshots for clarity:
http://zmcartor.github.io/code/2014/02/24/slim-xctest-targets
The advantage of this approach is test target builds much much faster.
In XCode 7, removing Host Application does not work for me. Indeed I use the following to avoid app runs.
Setup Test Scheme Arguments
in main.m
static bool isRunningTests()
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* testEnabled = environment[#"TEST_ENABLED"];
return [testEnabled isEqualToString:#"YES"];
}
modify main()
int main(int argc, char * argv[]) {
#autoreleasepool {
if (isRunningTests()) {
return UIApplicationMain(argc, argv, nil, nil);
} else {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
}
If the tests are for code that can run on desktop and mobile, you can run them without a simulator or hosting them within your app.
The trouble is that you cannot use the scheme chooser for your normal target (desktop or iOS) to run the test.
The following worked for me in Xcode6.
File > New Target...
Select Cocoa Testing Bundle from the OS X category.
Take care to select None from the target drop-down.
Click Finish. Add the relevant files to the new target as described above.
Now create a scheme to run the test.
Click the schemes chooser top-right and choose New Scheme..., click the drop-down and navigate down the list to the new target. Now you can choose the scheme from the schemes chooser, and use ⌘U to run the tests.
I just wasted a morning on this.
Project was created in XCode 4 and used SenTesting.
Tried migrating tests on XCode 5/XCTTest
Had same issue - app ran in simulator and test never started
after trying everything (change from app to logic tests, change to XCTest, remove SenTesting)
gave up created a clean XCode 5 project.
Added all my files in and tests ran ok.
May still have issues with Storyboard as these were built with XCode 4.
Drastic but it works so keep it as last resort.
On XCode5, the app does start. This answer shows how to change its delegate when running unit tests so that it exits right away: https://stackoverflow.com/a/20588035/239408
Since I upgraded from Xcode 3.2.3 to 3.2.4 and iOS 4.0.1 to iOS 4.1 SDK, when I set a breakpoint in my code and single-step over instructions, at each step, the debugger will spit one or more of that line:
Assertion failed: (cls), function getName, file /SourceCache/objc4_Sim/objc4-427.1.1/runtime/objc-runtime-new.m, line 3939
It doesn't happen on a specific line or for a specific instructions. I have a few breakpoints in my code and each time I hit one of those, the debugger starts spewing those messages. It doesn't seem to have any detrimental effect as the program works correctly. It's just very annoying to retrieve the information in the console when there are tens of those lines. I'm sure they're not displayed for nothing but I haven't found what the problem might be and what instruction might cause it. If I don't hit a breakpoint, then I don't see any of those lines. I did clean and rebuild my project multiple times to no avail.
Does anybody have any idea what this is?
I ran into this - and here's the reason mine happened: I had used
+localizedStringFromDate:dateStyle:timeStyle: in my code. Worked fine on the iPhone, but it's not available pre-4.0 SDK, so it coughed on the iPad. See if you're calling some routine that's either no longer available in the SDK, or available only in later versions. Frankly, I can't wait for 4.1 on the iPad!
-Owen
I'm also having this problem, in an iPad app originally written in Xcode 3.2.4 using the iOS 3.2 SDK, now being debugged in Xcode 3.2.5 using the 4.2 SDK, but only when I set the simulator to the 3.2 iOS Deployment Target (so I can run in the 3.2 simulator). Every stop at a breakpoint in the debugger, I get this assert repeated eight times. Single-stepping over a line gets two more.
What I can't understand is I haven't added any code to the project since I last run it in Xcode 3.2.4 and iOS SDK 3.2, so I can't have added any calls that were not present in that SDK or else it wouldn't have compiled.
Until someone finds an answer to this, I think the only workaround (so I can continue debugging my code in a 3.2 environment) is to reinstall Xcode 3.2.4 and use the 3.2 SDK and simulator.
I had this problem when I was running on simulator "iPad 3.2 simulator". This problem disappeared when I switched the simulator to "iPad 4.3 simulator"
I have exactly the same issue. I know it's not the complete answer but here's what I could find.
The relevant function getName looks like this:
/***********************************************************************
* getName
* fixme
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static const char *
getName(struct class_t *cls)
{
// fixme hack rwlock_assert_writing(&runtimeLock);
assert(cls);
if (isRealized(cls)) {
return cls->data->ro->name;
} else {
return ((const struct class_ro_t *)cls->data)->name;
}
}
So gdb is complaining that the assertion assert(cls) is failing. Which means that getName somehow gets a NULL pointer as an argument.
Which is kinda funny, where could we be asking for the name of a NULL class?
Hope this helps...
I also have the same problem; I don't have a solution but I'm able to work around it. In short, I suggest you add more breakpoints...
I noticed in the call stack that it's actually the debugger that is misbehaving. The function gdb_class_getClass calls getName, presumedly this is passing NULL instead of (say) MyClass. The code that I'm trying to debug is a method of MyClass. So, thinking that the debugger has a problem with MyClass, I set a breakpoint at a line outside of any code of MyClass (ie the line that calls the method on MyClass) and hit continue when the program breaks. This seems to resolve the problem in my case. (Note that auto-continue doesn't work.)
To be clear:
//Set breakpoint here
[myClassInstance buggyMethod];
My buggyMethod is actually in another file:
...
-(void)buggyMethod {
//This is where I set my 'real' breakpoint
Hope that helps.
I'm having a similar problem, but mine is with creating a custom view with Core Text in it. As soon as my view's drawRect calls the line
CTFontRef titleFont = CTFontCreateWithName(CFSTR("Baskerville"), 40.0f, NULL);
It hangs the app, whether in the simulator or on the device. Bizarrely, I can rectify this by alloc-initing another UIKit text component in the View Controller's viewDidLoad method... I don't even have to add it as a subview. It's like it needs some common text elements loaded before Core Text can load in fonts.
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
}
Weird.