Swift: overriding an initializer that takes an NSInvocation
Asked Answered
K

1

9

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?

Kalong answered 30/6, 2014 at 21:42 Comment(1)
As a workaround, maybe you can try mocking your object. You will be able to redirect the init call.Yun
T
1

I'm not os sure if I got it right, but checking the code you suggested you should get a compiler Error like: enter image description here

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.

Thermosetting answered 19/11, 2014 at 6:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.