An error occurs in the overridden function of XCUITest - swift

An error occurs in the overridden function of XCUITest.
I have never mentioned XCUITest.
The error is: "Method does not override method in superclass".
This happens when you change Xcode from version 11.4 beta 2 to 11.3.1 and build.
what should I do?
import XCTest
class SampleAppUITests: XCTestCase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testLaunchPerformance() throws {
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
// This measures how long it takes to launch your application.
measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
XCUIApplication().launch()
}
}
}
}

Explained in the release notes:
https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_beta_3_release_notes
You (the template) are calling methods that don’t exist when you use Xcode 11.3.1 or before. Use availability to replace setUpWithError and tearDownWithError (Swift 5.2) with simple setUp and tearDown (Swift 5.1).

Related

XCTest class func setUp() method how to handle failures

So Apple has an example of how the setUp and TearDown methods should be used that looks like this:
class SetUpAndTearDownExampleTestCase: XCTestCase {
override class func setUp() { // 1.
// This is the setUp() class method.
// It is called before the first test method begins.
// Set up any overall initial state here.
}
override func setUpWithError() throws { // 2.
// This is the setUpWithError() instance method.
// It is called before each test method begins.
// Set up any per-test state here.
}
override func setUp() { // 3.
// This is the setUp() instance method.
// It is called before each test method begins.
// Use setUpWithError() to set up any per-test state,
// unless you have legacy tests using setUp().
}
func testMethod1() throws { // 4.
// This is the first test method.
// Your testing code goes here.
addTeardownBlock { // 5.
// Called when testMethod1() ends.
}
}
func testMethod2() throws { // 6.
// This is the second test method.
// Your testing code goes here.
addTeardownBlock { // 7.
// Called when testMethod2() ends.
}
addTeardownBlock { // 8.
// Called when testMethod2() ends.
}
}
override func tearDown() { // 9.
// This is the tearDown() instance method.
// It is called after each test method completes.
// Use tearDownWithError() for any per-test cleanup,
// unless you have legacy tests using tearDown().
}
override func tearDownWithError() throws { // 10.
// This is the tearDownWithError() instance method.
// It is called after each test method completes.
// Perform any per-test cleanup here.
}
override class func tearDown() { // 11.
// This is the tearDown() class method.
// It is called after all test methods complete.
// Perform any overall cleanup here.
}
}
As you can see in the first method override class func setUp() overall inital state is suppost to be set. I have a simple setup phase for the application. But if this fails in some way. Then the test just get ignored like it never ran instead of marked as failure.
This is what the log says:
:0: error: simpleUITest : Failed to get matching snapshot: No
matches found for first query match sequence: Descendants matching type Cell -> Elements matching predicate '"login_button" IN identifiers', given input App element pid: 9849 (no attribute values
faulted in) Test Suite 'simpleUITest' failed at 2021-01-20
10:49:42.684. Executed 0 tests, with 1 failure (0 unexpected) in
0.000 (13.204) seconds
How can I get this to report as a test failure rather then just having XCTest ignore it?
Based on the docs, you have at least two options to fail a test from setUp:
Before each test begins, XCTest calls setUpWithError(), followed by setUp(). If state preparation might throw errors, override setUpWithError(). XCTest marks the test failed when it catches errors, or skipped when it catches XCTSkip.
and
Tip
You can include test assertions in a test case's setUp(), setUpWithError(), tearDown(), and tearDownWithError() instance methods. Any such assertions will be evaluated as part of every test method's run.
It isn't clear what you tried from your question. Do you have an assertion in setUp as suggested in the second option? Note that this only applies to the non-class setUp

Debugging window doesn't show print statements

I've been able to see print statements in the debugging window for my app. When I create a 'mock up' program (small trial app) to learn about Swift testing, none of the print statements in my LifecycleTests.swift file under the FirstTests folder display in the debugging window.
import XCTest
class LifecycleTests: XCTestCase {
override class func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
print("In class setUp.")
// NSLog("In class setUp.")
}
override class func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
print("In class tearDown.")
// NSLog("In class tearDown")
}
override func setup() {
print("In setup.")
// NSLog("In setup")
}
override func tearDown() {
print("In tearDown.")
// NSLog("In tearDown.")
}
func testExample() {
print("Starting test.")
// NSLog("Starting test.")
addTearDownBlock {
print("In first tearDown block.")
// NSLog("In first tearDown block.")
}
// print("In middle of test.")
NSLog("In middle of test.")
addTearDownBlock {
print("In second tearDown block.")
// NSLog("In second teardown block.")
}
print("Finishing test.")
// NSLog("Finishing test.")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
You can only get console output from one target at a time. Your console output is set to come by default from your app target, not your test target.
If you just run a test containing a print statement, you won't see any debugger output:
That test has a print statement, but we ran it and nothing appeared in the console.
Okay, but now let's trick the console into seeing the input from the test target. To do so, put a breakpoint in the test:
We step over the print statement and it prints to the console, along with a lot of other useful info about the test:
The interesting thing is that once you've used this trick, you can take the breakpoint away. The test target continues to be the console source until you run the app itself again.
The trick is a weird one but it appears to be the only way. Apple actually acknowledges it in an allusive way in their docs where they say:
if you have been actively engaged in debugging, any output from the debugging session also appears [in the console]
Evidently "actively engaged in debugging" means you've put a breakpoint in the test.

Unable to access Main Target Methods when Adding Tests to OSX Project in Swift

I have tried adding a testing bundle to my Project which seems to have succeeded.
However when I try to create instances of the Classes in my main project- I am unable to see them.
The Project seems to build fine - but I can' instantiate any of the test objects
Any ideas how to access them
Example Class to Test:
class EmailHelper: NSObject {
func generateEmailBody (greeting: String, bodyContent: String) -> String {
//Content goes in here
return message
}
}
import XCTest
class MyProject_DesktopTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// The Test would go in here but I can't seem to resolve EmailHelper class- it generates a lint error
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
}
I managed to get it working by adding Testable to the top of the class( This appears to be OSX specific issue)
import XCTest
#testable import MyProjectName // <--- This was the missing bit.... :)
class MyProject_DesktopTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// The Test would go in here but I can't seem to resolve EmailHelper class- it generates a lint error
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
}
Also be sure to clean your project after adding it an it seems to work.

Unable to register NSUndoManager in Swift 6.1 GM seed2

I am unable to get NSUndoManager to function in Swift Xcode release 6.1 GM Seed 2. I've read several times the article How do I register NSUndoManager in Swift? but I can't make it work in 6.1.
Here is a code snippet showing my attempt:
func zoomFractalClick(imagePoint: NSPoint?) {
//NSLog("Point zoomed \(imagePoint)")
if imagePoint == nil { return }
let tag = zoomPopUp.selectedItem!.tag
// Try setting undo/redo
undoManager.registerUndoWithTarget(self, selector: Selector("resetFractalDef"),
object: StructWrapper<MJFractalDefinition>(object: fractalDef))
//(undoManager.prepareWithInvocationTarget(self) as AppDelegate).
// resetFractalDef(StructWrapper<MJFractalDefinition>(object: fractalDef))
fractalDef.zoomBounds(centerPoint: imagePoint!, zoomPower: Double(tag))
drawFractal()
}
func resetFractalDef( fractalDef: StructWrapper<MJFractalDefinition>) {
self.fractalDef = fractalDef.object
drawFractal()
}
class StructWrapper<T> {
let object: T
init( object: T) {
self.object = object
}
}
Using the 'simple' method, everything compiles and runs correctly even saving the Undo. However when I select Undo from the Edit menu, I get the error that it can't find the selector 'resetFractalDef'.
I've also tried the prepare with invocation method of Undo, and it fails at the point where it tries to prepare the undo with invocation target reporting 'EXC_BREAKPOINT'.
Please, any help would be appreciated. I am a Java programmer learning to program in the Apple environment mostly enjoying the using Swift.

Swift: overriding an initializer that takes an NSInvocation

I'm trying to create a reusable test harness in Swift with the idea that subclasses will extend the test harness to provide the instance under test, and can add their own subclass-specific test methods, something like this:
class FooTestHarness: XCTestCase {
let instance: Foo
init(instance: Foo) {
self.instance = instance
}
func testFooBehavior() {
XCTAssert(instance.doesFoo())
}
}
class FooPrime: Foo {
func doesFooPrime(): Bool { /* ... */ }
}
class FooPrimeTests: XCTestCase {
init() {
super.init(FooPrime())
}
func myInstance(): FooPrime {
return instance as FooPrime
}
func testFooPrimeBehavior() {
XCTAssert(myInstance().doesFooPrime())
}
}
However, when XCode's testrunner tries to run FooPrimeTests, it doesn't call the no-arg init(), it calls init(invocation: NSInvocation!) (and fails because there isn't one). I tried to override this in FooTestHarness:
init(invocation: NSInvocation!, instance: Foo) {
self.instance = instance
super.init(invocation)
}
and in FooPrimeTests:
init(invocation: NSInvocation!) {
super.init(invocation, FooPrime())
}
but this fails with the message 'NSInvocation' is unavailable.
Is there a workaround?
I'm not os sure if I got it right, but checking the code you suggested you should get a compiler Error like:
Which actually I reckon is quite normal since your FooPrimeTests is just subclassing XCTestCase which has got different init like:
init!(invocation: NSInvocation!)
init!(selector: Selector)
init()
Probably when you posted you're question you're running on an older version of Swift, (I'm currently running it on the Xcode Beta 6.2) that's why you can't see the error. But, and I say again if I got your point right, your class FooPrimeTests can't see you custom initializer just because is sublcassing XCTestCase, rather then FooTestHarness. Which is the class where the init(instance: Foo) is defined.
So you might probably want to define FooPrimeTests as subclass of FooTestHarness. That way you should be able to correctly see your initializer. Hope this help.