iOS - 运行Swift单元测试时出现“找不到MyProject-Swift.h文件”的错误

101

我正在尝试为我的项目设置单元测试。 这是一个已经存在的Objective-C应用程序,最近我添加了一个Swift类。我已经设置了'MyProject-Swift.h'和Swift桥接文件(包括'MyProject'和'MyProjectTest'),并且我能够使用Objective-C和Swift代码构建和运行应用程序。

然而,现在我想对新的Swift类运行一些单元测试。 我设置了我的测试文件,它看起来像下面这样:

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.
        }
    }

}

当我将应用程序作为测试运行时,出现了这个错误:

'MyProject-Swift.h' file not found

我不确定为什么这只会在尝试运行测试时发生。有什么建议吗?


1
@Coveloper - 你是如何为'-Swift.h'文件设置目标的呢?它不是实际存在于项目中的文件,而是在Xcode编译时生成的。 - JimmyJammed
1
这是我之前关于“我也遇到了'MyProject-Swift.h'文件找不到的错误”的评论的更新:我通过将MyProjectTests目标的Product Module Name设置为MyProject而不是MyProjectTests来找到了一种解决方法。因此,现在两个目标(MyProject和MyProjectTests)都具有相同的Product Module Name。这很奇怪,但它可以工作,并且风险很低,因为它是测试目标。我应该提到我的项目名称实际上像My-Project,因此My_Project是实际的模块名称。 - finneycanhelp
7
"MyProject-Swift.h"文件生成于"$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources"路径下。我最终将其添加到了我的单元测试目标的Header Search Paths中。 - gagarwal
2
@gagarwal 将"$(TARGET_TEMP_DIR)/../$(PROJECT_NAME).build/DerivedSources"添加到我的单元测试目标的头文件搜索路径中,这个方法行得通。 :) 将这个评论转化为一个SO答案,我会授予你奖励,并让其他人清楚地知道这是一个很好的答案。 - finneycanhelp
1
我很高兴它对你有所帮助。我已将其添加为答案。希望苹果公司能尽快提供一些解决方案。 - gagarwal
显示剩余4条评论
11个回答

152

@fabb 不是这样的——TARGET_NAME通常是你测试目标中类似于“<产品名称>测试”的东西。但是,如果你的产品名称中有空格,这个解决方案就不起作用了。请参见我的下面的答案获取解决方案。 - Christopher Pickslay
2
只是一条说明,我不得不添加搜索路径,并将其设置为“递归”。这可能很明显,但在我这样做之前它几次都没有起作用;我认为它会进入子文件夹。 - Miro
很棒的解决方案! - Hsiao-Ting
1
对于我的项目,$(TARGET_TEMP_DIR) 没有起作用。最终我使用了 $CONFIGURATION_TEMP_DIR/{myTargetName}.build/DerivedSources - Jordan
2
我目前遇到了这个问题,似乎仍然无法解决。我已经尝试了这个线程上的所有方法,但仍然出现问题 - 已经运行了最新版本。 - RichAppz
显示剩余3条评论

37

感谢 @gagarwal 解决了这个问题。在我们的情况下,产品名称有一个空格,在 $PROJECT_NAME 中被折叠了,因此我必须硬编码它。此外,使用 $CONFIGURATION_TEMP_DIR 而不是 $TARGET_TEMP_DIR,可以从路径中删除父目录 (../)。因此,解决方案是在测试目标的头文件搜索路径中添加以下内容:

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

或者,如果您的产品不包含空格:

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

还解决了单元测试 Core Data 代码生成类的问题。 - Elise van Looij

14
在Xcode 6.1版本的发布说明中,发现了这个已知问题...搜索“-swift.h”在发布说明中 https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc6_release_notes.html

用Objective-C编写的测试无法导入应用程序目标的Swift生成接口头文件($(PRODUCT_MODULE_NAME)-Swift.h),因此无法用于测试需要此头文件的代码。

应使用Swift编写Swift代码的测试。用于框架目标的Objective-C编写的测试可以通过使用@import FrameworkName;导入框架模块来访问Swift生成的接口。(16931027)

请查看@gagarwal下面的解决方法,它是可行的!


9

我想你说的是与我类似的问题;这是我的设置。

我有一个在Swift中定义的对象:

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

这个类随后被用于 Objective-C 对象的初始化程序中:

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

@interface Bar: NSObject

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

@end

这导致我的 Bar 单元测试无法编译,因为 MyProject-Swift.h 标头文件不存在,单元测试目标无法看到它。@hyouuu 分享的发布说明很到位——但我正在测试 Objective-C 类,不是 Swift 类!我将 Bar 的头文件更改为使用前向类引用来修复这个问题:
// file Bar.h
@class Foo;

@interface Bar: NSObject

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

@end

我随后在 Bar.m 中包含了 MyProject-Swift.h,一切都正常了。我的用 Objective-C 编写的 Objective-C 对象的测试成功地编译并继续运行,我也可以为用 Swift 编写的 Swift 对象编写新测试。

希望这可以帮到你!


你的解决方案不允许在 Bar.m 中使用 Foo 的 API。 - Yevhen Dubinin
2
当然可以 - 这就是在 .m 文件中包含 MyProject-Swift.h 的作用。 - dpassage
现在我知道,即使没有导入Swift.h文件,使用Swift类名也是可能的,只需使用@class。 - Tamás Sengel

4

在尝试了所有相关内容后,对我有效的方法运行应用程序,即使它仍然显示“找不到ModuleName-Swift.h文件”的错误。

这个问题消失了,我的应用程序也可以正常工作。我想我应该更早地考虑到这一点... 错误会继续出现,但是在运行应用程序后,它总是会再次消失。因此,对我来说问题并没有真正解决,但我现在可以继续处理其他主题...


是的,这是一个解决方案,可以消除那个“未找到”的错误。 - Vijay Kumar Kanta
即使现在只是运行应用程序,编译仍然失败。修复这个问题,苹果! - ScottyB
1
如何在不先构建应用程序的情况下运行它?当我在Xcode 14.3中点击播放按钮时,会出现此错误。 - sushrut619

1
一个简单的


@testable import MyProject

已经为我完成了这项工作。


0

奇怪的是,我也遇到了同样的错误,但只有在针对设备(而不是模拟器)时才会出现。在运行测试之前,我会看到“ MyProjectNameTests-Swift.h”导入语句旁边的红色感叹号。

然而,有趣的是,如果我继续运行测试(尽管出现了这个明显的构建错误),那么在此后发生的构建阶段中,XCode实际上会生成“ MyProjectNameTests-Swift.h”文件,并且测试可以正常运行!

因此,在我的情况下,显然没有必要使用其他解决方案,尽管我相信它们也可以起作用。

我还应该注意,在此之前我删除了我的DerivedData目录,因此也许这也是一个值得尝试的步骤。


0

在我的一个客户项目中,他们直接将框架添加到了项目中。我通过以下方式解决了这些错误:

  • 命令1
  • 选项命令J
  • 现在在过滤器中输入框架名称(导致错误的那个)
  • 选择该框架
  • 选项命令1
  • 在目标成员资格中选择您的*UITests目标


-1

mySwiftClassTests(以及您想在Objective-C中使用的任何其他Swift类)需要标记为@objc

@objc class MySwiftClassTests: XCTestCase

-1

我尝试添加其他答案提到的文件路径,但无法使其正常工作。后来我意识到它所抱怨的文件甚至没有被测试。我只需要使用正确的实用程序侧边栏将其从测试目标中移除即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接