10

I have the following code (trying to avoid implicit unwrapping):

class MyTests: XCTestCase {

    var viewController: ViewController

}

But I'm getting the following error:

Class 'MyTests' has no initializers

I fixed with this:

class MyTests: XCTestCase {

    var viewController: ViewController

    override init() {
        self.viewController = ViewController()
        super.init()
    }
}

Would be a issue using init() in XCTest class?
I'm using Swift 4, Xcode 9.2.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
user2924482
  • 8,380
  • 23
  • 89
  • 173

3 Answers3

22

I understand that you'd like to avoid implicitly unwrapping, but unfortunately (unless you want to go through the trouble of writing your own test runner), you don't have control over which initializer is called when the tests are run.

You could get around this by implicitly unwrapping, as you know, and setting the value of the property in setUp(), which gets called before every test, so you can be sure the property will not be nil during your tests. This is relatively safe.

class MyTests: XCTestCase {

    var viewController: ViewController!

    override function setUp() {
        super.setUp()
        self.viewController = ViewController()
    }
}

Alternatively, you could make the property lazy, which means that it does not have to be implicitly unwrapped. This means that the property does not have to be initialized during object initialization so you don't need to write a new initializer, but will be initialized the first time it is accessed.

class MyTests: XCTestCase {

    lazy var viewController: ViewController = {
        return ViewController()
    }()
}
Oletha
  • 7,324
  • 1
  • 26
  • 46
2

When writing XCTest then no need of writing initializer.

XCTestCase providing method to prepare test items before execution of actual test.

Declare viewController as explicitly unwrapped(to avoid implicit unwrapping) as below.

class MyTests: XCTestCase {

    var viewController: ViewController!

}

Overrider below 2 methods always in your each XCTestCase class.

setUp is to prepare variables before actual test execution. Initialize viewController in setUp.

override func setUp() {
        super.setUp()
        self.viewController = ViewController()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

tearDown is to release variables and other resources after finishing test. Release viewController in tearDown.

override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class
        self.viewController = nil
        super.tearDown()
    }
technerd
  • 14,144
  • 10
  • 61
  • 92
0

Actually, setup() called in every test method invocation.

/*!
 * @method -setUp
 * Setup method called before the invocation of each test method in the class.
 */
- (void)setUp;

So, why do u need to create viewController, let's say, 3 times for 3 test methods in the current XCTests subclass? You can try to declare your variables outside XCTests subclass

Zaporozhchenko Oleksandr
  • 4,660
  • 3
  • 26
  • 48