159

I simply want to include my Swift class from another file, like its test

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel { }

PrimeNumberModelTests.swift

import XCTest
import PrimeNumberModel  // gives me "No such module 'PrimeNumberModel'"

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()  // "Use of unresolved identifier 'PrimeNumberModel'"    
}

Both swift files are in the same directory.

clearlight
  • 10,772
  • 11
  • 48
  • 65
joseph.hainline
  • 21,512
  • 16
  • 50
  • 70
  • 1
    please check https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid/TP40014097-CH17-XID_251 – Nitin Gohel Jun 04 '14 at 05:40
  • 2
    According to apple docs you don't need an import when both files have same target. Sadly tests have a different target. One possible solution might be to do an import statement using yourModule/PrimeNumberModel. – Alex Reynolds Jun 04 '14 at 22:27
  • @joseph.hainline I am facing same issue. How it will be resolved? I am stuck now. – Developer Sep 25 '14 at 07:07

13 Answers13

132

I had the same problem, also in my XCTestCase files, but not in the regular project files.

To get rid of the:

Use of unresolved identifier 'PrimeNumberModel'

I needed to import the base module in the test file. In my case, my target is called 'myproject' and I added import myproject and the class was recognised.

Forge
  • 5,854
  • 6
  • 41
  • 58
H6.
  • 26,822
  • 12
  • 70
  • 78
  • 1
    Yep, this is the way to do it. Except I think it's not really your project that you're importing, but rather the target containing the code that you want to test? – Michael Jun 05 '14 at 16:23
  • 1
    Thanks man, this saved me a lot of time. You need to `import `. – Jeffery Thomas Jun 07 '14 at 02:49
  • 2
    This needs more upvotes. The answers advising to just add the .swift file to the test target are not exactly wrong, but it's not the way it should be done – below Jun 21 '14 at 22:43
  • 10
    But what to do with my project name "Wildlife League", which has space in it? – allenlinli Jul 08 '14 at 10:36
  • 59
    Starting with Beta 4, you'll also need to make sure your access control settings are correct. You'll need to explicity set both the class you're testing and the functions you're testing within that class as `public`. Otherwise the `XCTestCase` subclass won't be able to "see" what you're trying to test. I wasted a few hours on this last night :) – Erik P. Hansen Aug 01 '14 at 16:33
  • I'm experiencing the same issue as OP, but the `import` didn't help. My target is called PresentAPIClient, but the only things listed in the module are `import Foundation` and `import UIKit`, unlike example projects, which seem to list the available interfaces for the module. All of my source files are included in the target under compile sources. – HighFlyingFantasy Aug 08 '14 at 15:07
  • 1
    @AllenLin: Good question. I had the same problem and solved it by just renaming my project. I did that by clicking on my projects top most item in the project navigator, pressing enter and removing any whitespaces. XCode will automatically handle renaming related files. – Jeehut Aug 13 '14 at 21:52
  • 1
    I had to manually change the "Test Host" entry in Build Settings of my Test target though. Check that also if you get any Mach-O Linker errors after renaming the project. – Jeehut Aug 13 '14 at 22:11
  • 2
    If I'm not mistaken, the **Product Module Name** (in target build settings) isn't always the same as the target's name and it's the module's name that should be used in the `import` statement – csch Aug 28 '14 at 08:34
  • I have remove the space in the name of my project but still it is showing the error No Such Module. Why? – Developer Sep 25 '14 at 07:19
  • I think the best practice would be to add the model swift file and any other files to the test target. Then you don't need to play games with the access modifiers and expose everything that you need to test. – Paul Solt Nov 19 '14 at 04:16
  • On top of doing this, I had to set the Target Membership in the File Inspector in the right sidebar of my swift file. – Morgan Chen Jan 27 '15 at 02:31
  • 3
    If a Swift target has a space in its name, you can import it by replacing the spaces with underscores in the import statement. "My Swift Class" becomes "My_Swift_Class". – Cin316 May 03 '15 at 22:47
  • As for Xcode 6.3.1, it's not needed to make every class public. I managed to make it working as described above with "internal" classes. – Arthur Gevorkyan Jun 26 '15 at 08:59
  • @ArthurGevorkyan: Xcode 6.4, Swift 1.x here; trying to access AppDelegate from XCTestCase subclass (which `import`s MyAppTargetName ). Marking app delegate class and methods as `public` works OK; marking as `internal` gives "Use of undelcalred identifier AppDelegate" in XCTestCase subclass. – Nicolas Miari Aug 05 '15 at 06:34
  • I tried: leaving AppDelegate and its properties/methods as `internal`, but modifying the target membership of AppDelegate.swift to include the test target too. This builds, but at runtime the test fails because `let delegate = UIApplication.sharedApplication().delegate as? AppDelegate` fails (either its `nil`, or an object of a different type - haven't checked ). If instead I make all `public` and remove target membership, it works. – Nicolas Miari Aug 05 '15 at 06:45
  • [continued] it turns out it is of the wrong type, not `nil`! It is the cast that fails. – Nicolas Miari Aug 05 '15 at 06:48
  • @NicolasMiari, does it mean that it's all right now with your setup? If yes, then congrats :) – Arthur Gevorkyan Aug 06 '15 at 13:03
  • @ErikP.Hansen you are a baws – Neil Japhtha Sep 05 '16 at 10:42
71

UPDATE Swift 2.x, 3.x, 4.x and 5.x

Now you don't need to add the public to the methods to test then. On newer versions of Swift it's only necessary to add the @testable keyword.

PrimeNumberModelTests.swift

import XCTest
@testable import MyProject

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()
}

And your internal methods can keep Internal

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel {
   init() {
   }
}

Note that private (and fileprivate) symbols are not available even with using @testable.


Swift 1.x

There are two relevant concepts from Swift here (As Xcode 6 beta 6).

  1. You don't need to import Swift classes, but you need to import external modules (targets)
  2. The Default Access Control level in Swift is Internal access

Considering that tests are on another target on PrimeNumberModelTests.swift you need to import the target that contains the class that you want to test, if your target is called MyProject will need to add import MyProject to the PrimeNumberModelTests:

PrimeNumberModelTests.swift

import XCTest
import MyProject

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()
}

But this is not enough to test your class PrimeNumberModel, since the default Access Control level is Internal Access, your class won't be visible to the test bundle, so you need to make it Public Access and all the methods that you want to test:

PrimeNumberModel.swift

import Foundation

public class PrimeNumberModel {
   public init() {
   }
}
Diogo T
  • 2,483
  • 1
  • 27
  • 36
  • is there any way to change the default Access Control? I had a funny case that it used to run without public modifier just fine, then I moved the test cases around, it suddenlly stopped working anymore. – Metaphox Sep 23 '14 at 17:50
  • I think that's not possible, at least for the current version of swift. – Diogo T Sep 24 '14 at 18:06
  • thanks. And I found out that my problem was that the swift file is not build to the test target with the test cases. – Metaphox Sep 25 '14 at 08:25
  • @Metaphox you should't build the class on the test target, take a look on a post that I wrote about this in more detail: http://blog.diogot.com/blog/2014/08/23/swift_access_control_and_testing/ – Diogo T Sep 26 '14 at 15:14
  • 1
    yes, that was exactly where I felt wrong -- I should not build the class swift file into the test case target. nice blog post! thanks. – Metaphox Sep 29 '14 at 08:51
  • 1
    If you have an project created with Xcode 5 or later and you are opting for the "public access, import target module" approach, double check the module name for your test target as it might be the same as the main target. If you are receiving a `No such module ` compile error in your test case you may want to check the `PRODUCT_MODULE_NAME` for the test target. Great answer Diogo. – Chris Apr 28 '15 at 17:13
  • Just in case someone else runs into this, you need to check where the settings are defined in the Project > Target hierarchy. Click the "Levels" option in the to left of the target settings editor (under the tab control) and make sure your **application target** has a `PRODUCT_MODULE_NAME` defined, but **not** the testing target. You might have accidentally defined the `PRODUCT_MODULE_NAME` at the project level instead of the target level, resulting in both your targets having the same module name. – Brian Gerstle Jul 07 '15 at 19:50
51

In the Documentation it says there are no import statements in Swift.

enter image description here

Simply use:

let primNumber = PrimeNumberModel()
Forge
  • 5,854
  • 6
  • 41
  • 58
Nitin Gohel
  • 48,603
  • 17
  • 104
  • 138
  • 2
    This worked but I had to close and reopen Xcode 6.0 for the class to finally show up. Try cleaning and building the project as well. – user3344977 Sep 22 '14 at 20:37
  • This seems to be new (or an issue) in the latest XCode 6.3 beta's, so the import statement is neccessary now. Also there is an import statement in Swift, to import modules. – Augunrik Mar 27 '15 at 18:32
  • According the provided documentation, this table with "No import statement" is related to the "Import from the same target" case. In case of XCTests you use different (test) target, so observe the "Importing External Frameworks" section of the article, there is another table: Any language framework -> Import into Swift -> import "FrameworkName" is needed – Igor Vasilev Jul 12 '15 at 18:57
  • If you see an issue in the editor, it's often that there's a test target that doesn't have the class included. So you probably build your runnable fine, but if any one of the targets is having an issue, it still shows the error. If you had selected one of those other targets, it wouldn't let you compile. – Joel Teply Oct 30 '15 at 18:34
35

Check target-membership of PrimeNumberModel.swift in your testing target.

Kendall Helmstetter Gelner
  • 73,251
  • 26
  • 123
  • 148
kimkkikki
  • 359
  • 2
  • 2
  • 1
    please add this as comment. – 4dgaurav Jun 09 '14 at 06:18
  • 9
    This person can't, he needs 9 more rep to do so (at time of writing). – AlbertEngelB Aug 28 '14 at 20:46
  • 1
    What the heck is a target? – User Oct 12 '14 at 01:55
  • Thanks this worked for me. Click on the class file. Check the the first tab of inspector column on the right. The second section is "Target Membership". Make sure the target/product you're trying to include the class is is selected. – Hairgami_Master Mar 27 '15 at 15:08
  • 1
    It's not strictly an answer to the question "how do I import...", but it did answer the question I had that brought me here (I forgot to add a new file to the target). So for me, and others that will arrive here by following the first google result for "swift unresolved identifier class", this **is** an answer (and not a comment). – noamtm Jun 01 '15 at 10:15
  • This can't solve the question for many scenarios, what this does is make the test app create a separate instance of the class, so if you are for example testing services, or components that can only be connected to one instance at a time you'll end up creating conflicts or getting the wrong data. – gbdavid Nov 25 '15 at 12:58
  • Including your app's code files in the test target can also cause all sorts of weird issues when your test target is compiling, [such as this one](http://stackoverflow.com/questions/26030951/ibdesignable-errors-when-adding-to-tests-target). I did this at first then realized just [importing the whole module](http://stackoverflow.com/a/34605030/2680007) is a better idea. – George WS Jan 05 '16 at 05:53
19

In Objective-C, if you wanted to use a class in another file you had to import it:

#import "SomeClass.h"

However, in Swift, you don't have to import at all. Simply use it as if it was already imported.

Example

// This is a file named SomeClass.swift

class SomeClass : NSObject {

}

// This is a different file, named OtherClass.swift

class OtherClass : NSObject {
    let object = SomeClass()
}

As you can see, no import was needed. Hope this helps.

Community
  • 1
  • 1
Fomentia
  • 646
  • 5
  • 10
6

According To Apple you don't need an import for swift files in the Same Target. I finally got it working by adding my swift file to both my regular target and test target. Then I used the bridging header for test to make sure my ObjC files that I referenced in my regular bridging header were available. Ran like a charm now.

import XCTest
//Optionally you can import the whole Objc Module by doing #import ModuleName

class HHASettings_Tests: XCTestCase {

override func setUp() {
    let x : SettingsTableViewController = SettingsTableViewController()

    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() {
    // This is an example of a functional test case.
    XCTAssert(true, "Pass")
}

func testPerformanceExample() {
    // This is an example of a performance test case.
    self.measureBlock() {
        // Put the code you want to measure the time of here.
    }
}

}

SO make sure PrimeNumberModel has a target of your test Target. Or High6 solution of importing your whole module will work

Alex Reynolds
  • 6,090
  • 4
  • 23
  • 42
6

I was able to solve this problem by cleaning my build.

Top menu -> Product -> Clean Or keyboard shortcut: Shift+Cmd+K

janisz
  • 5,933
  • 4
  • 31
  • 62
Peter Fisher
  • 61
  • 1
  • 1
5

As of Swift 2.0, best practice is:

Add the line @testable import MyApp to the top of your tests file, where "MyApp" is the Product Module Name of your app target (viewable in your app target's build settings). That's it.

(Note that the product module name will be the same as your app target's name unless your app target's name contains spaces, which will be replaced with underscores. For example, if my app target was called "Fun Game" I'd write @testable import Fun_Game at the top of my tests.)

George WS
  • 3,381
  • 5
  • 20
  • 37
3

Check your PrimeNumberModelTests Target Settings.

If you can't see PrimeNumberModel.swift file in Build Phases/Compile Sources, add it.

Forge
  • 5,854
  • 6
  • 41
  • 58
Bumseok
  • 923
  • 8
  • 6
2

You need to add a routine for the compiler to reference as an entry point, so add a main.swift file, which in this case simply creates an instance of your test file:

main.swift

PrimeNumberModelTests()

Then compile on the command line (I am using El Capitan and Swift 2.2):

xcrun -sdk macosx swiftc -emit-executable -o PrimeNumberMain PrimeNumberModel.swift PrimeNumberModelTests.swift main.swift

In this case, you will get a warning: result of initializer is unused, but the program compiles and is executable:

./PrimeNumberMain

CAVEAT: I removed the import XCTest and XCTestCase type for simplicity.

Rose Kunkel
  • 2,768
  • 2
  • 22
  • 50
Pinecone
  • 351
  • 3
  • 8
1

So, you need to

  1. Import external modules you want to use
  2. And make sure you have the right access modifiers on the class and methods you want to use.

In my case I had a swift file I wanted to unit test, and the unit test file was also a swift class. I made sure the access modifiers were correct, but the statement

import stMobile

(let's say that stMobile is our target name)

still did not work (I was still getting the 'No such module' error), I checked my target, and its name was indeed stMobile. So, I went to Build Settings, under packaging, and found the Product Module Name, and for some reason this was called St_Mobile, so I changed my import statement

import St_Mobile

(which is the Product Module Name), and everything worked.

So, to sum up:

  1. Check your Product Module Name and use the import statement below in you unit test class

    import myProductModuleName
    
  2. Make sure your access modifiers are correct (class level and your methods).

Cloud9999Strife
  • 2,766
  • 2
  • 27
  • 40
1

Instead of requiring explicit imports, the Swift compiler implicitly searches for .swiftmodule files of dependency Swift libraries.

Xcode can build swift modules for you, or refer to the railsware blog for command line instructions for swiftc.

mcandre
  • 19,306
  • 17
  • 77
  • 140
1

As @high6 and @erik-p-hansen pointed out in the answer given by @high6, this can be overcome by importing the target for the module where the PrimeNumberModel class is, which is probably the same name as your project in a simple project.

While looking at this, I came across the article Write your first Unit Test in Swift on swiftcast.tv by Clayton McIlrath. It discusses access modifiers, shows an example of the same problem you are having (but for a ViewController rather than a model file) and shows how to both import the target and solve the access modifier problem by including the destination file in the target, meaning you don't have to make the class you are trying to test public unless you actually want to do so.

mr_sd
  • 91
  • 1
  • 7