101

I am trying to setup Unit Testing for my project. It is an existing Objective-C app, that I have recently added one Swift class to. I have setup the 'MyProject-Swift.h' and Swift Bridging files (both 'MyProject' and 'MyProjectTest') and I am able to build and run the app just fine using both Objective-C and Swift code.

However, now I want to run some Unit Tests on the new Swift class. I setup my test file and it looks like the following:

MySwiftClassTests.swift:

import UIKit
import XCTest
import MyProject

class MySwiftClassTests: XCTestCase {

    override func setUp() {
        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.
        }
    }

}

I get this error when running the app as Test:

'MyProject-Swift.h' file not found

I am not sure why this happens only when trying to run the Tests. Any suggestions?

JimmyJammed
  • 9,598
  • 19
  • 79
  • 146
  • Did you add MyProject-Swift.h to your Test Target? – jonbauer Oct 24 '14 at 23:13
  • 1
    Add updates on this? I'm facing the same problem... – hyouuu Nov 03 '14 at 11:56
  • 1
    @Coveloper - How are you able to set the targets for the '-Swift.h' file? It is not a real file that sits in the project, but instead compiled by Xcode on build. – JimmyJammed Nov 03 '14 at 19:34
  • I also get the 'MyProject-Swift.h' file not found error. The -Swift.h import statement and error is in my Objective-C .m code and not my test code. So, @dpassage suggestion below won't work for me. In fact, if I delete all the tests I still get this error. This only happens when compiling the MyProjectTests target. – finneycanhelp Jan 19 '15 at 17:18
  • 1
    Here's an update to my "I also get the 'MyProject-Swift.h' file not found error.." comment above: I found a workaround by setting the MyProjectTests target's Product Module Name to MyProject as opposed to MyProjectTests. So, now both targets (MyProject and MyProjectTests) have the same Product Module Name. That's weird, but it works and is low risk since it's the Test target. I should mention that my project name is actually like My-Project thus My_Project is the actual module name.) – finneycanhelp Jan 19 '15 at 18:23
  • Update to my update: A smart co-worker of mine pointed out that for this specific case, I can just remove the .m file from the Tests target that is doing the -Swift.h import statement since it is not being tested. – finneycanhelp Jan 19 '15 at 19:39
  • 7
    "MyProject-Swift.h" file is generated at "$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources". I end up adding this to Header Search Paths for my Unit Test target. – gagarwal Jan 19 '15 at 20:03
  • 2
    @gagarwal Adding "$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources" to the Header Search Paths for my Unit Test target worked. :) Make a SO answer out of that comment and I can award you the bounty plus make it clear for others what a great answer it is. – finneycanhelp Jan 24 '15 at 15:51
  • 1
    I am glad it helped you. I have added this as an answer. Hopefully Apple will provide some solution at their end soon. – gagarwal Jan 25 '15 at 16:44

11 Answers11

152

"MyProject-Swift.h" file is generated at following path:

"$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources"

I end up adding this to Header Search Paths for my Unit Test target.

Also as @hyouuu pointed out about being the known issue, hopefully Apple will provide some good solution at their end. Until I believe we need to use this above solution.

https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc6_release_notes.html

Cœur
  • 37,241
  • 25
  • 195
  • 267
gagarwal
  • 4,224
  • 2
  • 20
  • 27
  • Awesome! Don't know why Apple don't mention this as a workaround. Also amazed that there aren't more people having this issue. Anyone with an existing Obj-C project converting things to Swift gradually will hit this issue. – mluisbrown Feb 08 '15 at 17:23
  • @fabb not true--the TARGET_NAME is generally something like ` Tests` in your testing target. However this solution doesn't work if your product name has spaces. See [my answer below](http://stackoverflow.com/a/29111547/214350) for a solution. – Christopher Pickslay Mar 17 '15 at 23:28
  • It doesn't work in Simulator. How can I get it to work? – Dmitry Jun 24 '16 at 05:36
  • @Dmitry It is working on simulator too. Are you having different test target for simulator? – gagarwal Oct 12 '16 at 20:51
  • 2
    Just a note, I had to add the Search Path, and set it as "recursive" specifically. Might be obvious, but it didn't work a few times until I did that; I assume it goes into subfolders then. – Miro Mar 07 '17 at 18:53
  • 1
    For my project, `$(TARGET_TEMP_DIR)` didn't work. I wound up using `$CONFIGURATION_TEMP_DIR/{myTargetName}.build/DerivedSources` – Jordan Jun 20 '18 at 16:23
  • 2
    I am currently having this problem and don't seem to be able to fix it still. I have tried everything on this thread and I am still getting the problem - running all the latest. – RichAppz May 15 '19 at 11:09
37

Thanks to @gagarwal for figuring this out. In our case the product name has a space, which is collapsed in $PROJECT_NAME, so I had to hard code it. Additionally, by using $CONFIGURATION_TEMP_DIR instead of $TARGET_TEMP_DIR, you can remove the parent directory (../) from the path. So the solution is to add the following to the Header Search Paths in your test target:

"$(CONFIGURATION_TEMP_DIR)/Product Name With Spaces.build/DerivedSources"

Or, if your product does not contain spaces:

"$(CONFIGURATION_TEMP_DIR)/$(PROJECT_NAME).build/DerivedSources"
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
14

Saw in the Xcode 6.1 release note, that this is a known issue... sign... Search for "-swift.h" in the release note https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc6_release_notes.html

Tests written in Objective-C cannot import the Swift generated interfaces header ($(PRODUCT_MODULE_NAME)-Swift.h) for application targets, and therefore cannot be used to test code that requires this header.

Tests for Swift code should be written in Swift. Tests written in Objective-C for framework targets can access the Swift generated interfaces by importing the framework module using @import FrameworkName;. (16931027)

Please see @gagarwal's workaround below which WORKS!

Michael Revlis
  • 1,463
  • 11
  • 14
hyouuu
  • 2,471
  • 2
  • 27
  • 37
9

I had a similar issue to yours, I think; here was my setup.

I had an object defined in Swift:

// file Foo.swift
@objc public class Foo {
    // ...
}

This class was then used in the initializer of an Objective-C object:

// file Bar.h
#import "MyProject-Swift.h"

@interface Bar: NSObject

- (instancetype)initWithFoo:(Foo *)foo;

@end

This made my unit tests for Bar not compile, since the MyProject-Swift.h header isn't real and the unit test target can't see it. The release note shared by @hyouuu is on point - but I'm not testing a Swift class, I'm testing an Objective-C class!

I was able to fix this by changing the header file for Bar to use a forward class reference instead:

// file Bar.h
@class Foo;

@interface Bar: NSObject

- (instancetype)initWithFoo:(Foo *)foo;

@end

I then included MyProject-Swift.h in Bar.m, and everything worked - my tests of Objective-C objects written in Objective-C compiled properly and continued running, and I could write new tests for Swift objects in Swift.

Hope this helps!

dpassage
  • 5,423
  • 3
  • 25
  • 53
4

After I tried out everything I could find on the topic, the thing that worked for me was actually running the app although it was still showing the 'ModuleName-Swift.h file not found' error.

It went away and my app works perfectly fine. I guess I should have considered that earlier... The error keeps coming back, but after running the app it always just goes away again. So the issue is not really solved for me, but I can continue working on other topics for now...

schrulnz
  • 41
  • 1
  • 5
1

A simple

@testable import MyProject

has done the job for me.

niggeulimann
  • 688
  • 6
  • 15
0

Strangely, I was seeing this same error, but only when targeting a device (not the simulator). Before running the test I would see the red exclamation point next to the import statement for "MyProjectNameTests-Swift.h".

However, funny thing is, if I just go ahead and run the test anyway (despite this apparent build error), then during the build phase that happens thereafter, XCode actually does generate the "MyProjectNameTests-Swift.h" file, and the test runs just fine!

So, at least in my case, there was no need for the other solutions here, evidently, although I believe they do work also.

I should also note that I deleted my DerivedData directory prior to this, so maybe that is a step also worth trying.

CommaToast
  • 11,370
  • 7
  • 54
  • 69
0

On one of my clients project they added frameworks directly in the project. I solved the errors like this;

  • Command 1
  • option command J
  • now type the framework name (that gives the error) in the filter
  • select the framework
  • option command 1
  • in Target Membership select your *UITests target

7RedBits.com
  • 454
  • 6
  • 6
-1

mySwiftClassTests (and any other swift classes you want to use in objective-c) needs to be marked @objc:

@objc class MySwiftClassTests: XCTestCase
whoKnows
  • 905
  • 2
  • 9
  • 27
-1

I couldn't get it to work by adding that filepath mentioned by other answers, but I realized the file where it was complaining wasn't even being tested. I just had to remove it from the test target using the Right Utilities Side Bar.

teradyl
  • 2,584
  • 1
  • 25
  • 34
-2

Adding a .swift file to that target fixes issue on it.

Dmitry
  • 14,306
  • 23
  • 105
  • 189