Cannot override init() function in Swift XCTestCase
Asked Answered
S

1

13

I'd like to override the init function for XCTestCase in UI testing for a few reasons:

  • To launch the app, outside of setUp() so that the app doesn't need to relaunch for every test (this is tedious and slows down tests)
  • To initialize other classes that provide general navigation through the app, which must me initialized with a test case (self).

What I have now looks like this:

import XCTest

class UITest: XCTestCase {

    let app = XCUIApplication()

    // Helper packages
    var helper: UITestHelper!

    override func setUp() {
        super.setUp()

        // Helper package instantiation
        helper = UITestHelper(withTestCase: self, forApp: app)

        continueAfterFailure = false
        app.launch()
    }

... tearDown(), tests ....

When I call:

override init() {
    super.init()
    foo()
}

I get Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Suppression answered 8/6, 2018 at 15:20 Comment(1)
A possible workaround is to use a lazy variable but please don't do that. It will create a dependency between your tests.Matchlock
D
14

init is not the designated initializer of XCTestCase. The designated initializer is initWithInvocation:. This takes an NSInvocation, which is not available in Swift. The only way to do what you're describing is in ObjC.

This isn't documented because it's not supported. It may be possible to achieve what you're describing, but it is likely to break in subtle ways, and you should explore other solutions to your problem.

The crashing is a byproduct of ObjC initialization semantics. Every ObjC class must respond to init (because it's inherited from NSObject). However, there are quite a few ObjC objects that do not initialize properly when init is called. (NSError is somewhat famous for this problem.) The only way to know is by documentation. The much more complex Swift initialization system is an attempt to remedy the problems in the ObjC initialization system.

I would break up your deeper goals into separate questions and ask how to address them (you should also make it very clear that you're talking about UI tests; while your code indicates that, it's not clear from the text). Make sure what you're describing isn't going to break Xcode 10's new parallel testing features, and changes to ordering.

Diphthong answered 8/6, 2018 at 15:44 Comment(2)
It will break test parallelization for one thing and it will make one test dependent on the others in the suite which is generally a bad thing.Matchlock
Thanks, I had this Thread 1: EXC_BAD_INSTRUCTION in my tests because of using NSError() in code I tested, after I removed it I got rid of this unexpected crash.Basir

© 2022 - 2024 — McMap. All rights reserved.