28

I have been trying to write test cases in Swift to test my ViewController. However, when I try to instantiate my own ViewController in a XCTestCase I get "Use of undeclared type 'ViewController' ". (ViewController is the name of my own UIViewController class)

enter image description here

Has anyone else faced this issue before? I am using Xcode 6 beta 5

hoomi
  • 1,882
  • 2
  • 16
  • 17

3 Answers3

49

Swift 1

You should add ViewController.swift file's target membership also as your test target also if you are not using framework. Select class file add to target as shown in image:

enter image description here

OR

If you are ViewController is within a framework : ViewController class is in different target and You are not declaring class with public access level. By default Classes are internal (Accessible within a target). Declare it as public and also make methods or properties as public if you want to access it i.e

public class ViewController: UIViewController {

    public var content: String!

    override public func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override public func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Swift 2 Update

In your test target, just import the module you want to test using the @testable keyword:

@testable import moduleToTest

You can now access public and internal symbols in your test target.

swift 2 Xcode 7 unit testing

Yatheesha
  • 10,412
  • 5
  • 42
  • 45
  • Thanks for your answer. I did change the class access to be public but I am still having the same problem. Do you know if I need to change anything in the configurations? – hoomi Aug 14 '14 at 10:50
  • Thanks @Yatheesha. Do you know where I can check the file target membership? (I am not very familiar with XCode) – hoomi Aug 14 '14 at 11:00
  • 1
    @hoomi Select ViewController.swift file . In the file inspector there is a Target membership option contains list of targets in your project , Check mark your test target. – Yatheesha Aug 14 '14 at 11:03
  • This solution solves the error but slows down the unit testing a lot because now instead of using a reference of the main target we are compiling code inside the tests. There must be a better way – Julio Bailon Feb 12 '15 at 19:51
  • @JulioBailon: in Swift 2, adding `@testable import [appName]` is Apple's suggested solution. – kakubei Jun 17 '16 at 17:17
  • @kakubei please note that my comment was when that testable import was not available. Also, testable import is not currently working on some applicationless extensions. Just confirmed with the Apple engineers at WWDC that we need to use the previous technique to make it work. I hope they will fix it for the final release. – Julio Bailon Jun 17 '16 at 20:00
3

I also got this error recently and none of the above steps fixed the problem, what did fix it was removing non-swift file from the Compile sources build phase in the Target you want to run tests on.

Make sure your app is actually compiling. This was failing silently and the error message wasn't helpful

enter image description here

amleszk
  • 6,192
  • 5
  • 38
  • 43
2

In swift 4 you can create a new unit test target, it should import the target you have selected as stated below

In order to test any logic inside the view controller you should have a reference to it so that in order to reach the viewController you should has a reference to the storyboard first as stated below

// Put setup code here. This method is called before the invocation of each test method in the class.
let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
    viewController = storyBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
    _ = viewController.view

The previous code should be inserted inside setUp method, this method is called each time the unit test is running. Note the viewController is a variable defined inside XCTestCase class as stated in the screenshot attached below

For now you can access any logic defined inside the viewController class by calling viewController.funCode or viewController.variable

enter image description here

DO NOT FORGET: in order to reach the view controller by storyboard you should identify. in order to do that you should go to storyboard, then select the viewController, then from the right panel, go to "show the identity inspector" and set a value for the storyboard ID = 'ViewController'

For more information please have a look at : https://github.com/msabukwaik/networking-example

  • that leads to a class conversion error... the problem its if you put the same class on both modules, the test and the testable, Xcode will understand they are different... – JBarros35 Feb 27 '20 at 12:05