Swift 测试给出错误 "Undefined symbols for architecture x86_64"

Swift test give error "Undefined symbols for architecture x86_64"

我正在 运行宁 swift test 从命令行到 运行 测试用例。这是测试用例:

import XCTest
@testable import vnk_swift

class KeyMappingTests: XCTestCase {
    static var allTests : [(String, (KeyMappingTests) -> () throws -> Void)] {
        return [
            // ("testExample", testExample),
        ]
    }

    func testExample() {
        let keyMapping = KeyMapping()
        XCTAssertNotNil(keyMapping , "PASS")
    }
}

这是输出消息。

如果我删除 KeyMapping 的用法,一切正常:

    func testExample() {
        // let keyMapping = KeyMapping()
        XCTAssertNotNil(true , "PASS")
    }

我尝试使用 class 时似乎出现了问题。 我该如何解决这个问题?

(我没有为这个项目使用Xcode,因为我从swift package init开始,这个项目的源代码在这里:https://github.com/trungdq88/vnk-swift

我看到在目录中您有 vnk-swift,但在导入语句和损坏的名称中您有 vnk_swift。也许这是处理连字符的 Xcode/compiler 错误。尝试在名称中没有连字符的目录和项目上重现,例如 vnkswift

希望对您有所帮助

我通过进行以下修改成功地构建和测试了您的程序包:

  • 将包名称重命名为 VnkSwift,由于某些原因,构建工具不喜欢包名称中的破折号,当生成的包名称中包含下划线时它也不起作用(因此将包重命名为 vnk_swift 以确保导入语句和包名称匹配不起作用)
  • 将测试文件夹重命名为 VnkSwiftTests 以便 link 人知道 link 反对什么;似乎这是 link 人知道 link 反对包裹
  • 的先决条件
  • 最后,将 main.swift 重命名为其他名称(我使用 utils.swift)。问题是 main.swift 的存在指示构建工具生成可执行文件,而针对可执行文件的 linking 效果不佳。重命名后,不得不注释if代码,因为全局运行代码只能属于main.swift.

总结:

  • 避免使用非字母数字包名称
  • 包名和测试目录名必须同步
  • 确保您没有 main.swift 文件以确保包可以 linked against

为什么单元测试不能针对 link 可执行文件?

这是因为测试包和可执行包都有全局执行代码(又名 main 函数),所以 linker 不知道该选择哪一个。从 Xcode 进行测试时,测试包会进入应用程序的上下文 - 它不会 link 反对它,就像这里的情况一样。

Xcode 在创建命令行工具时也有这个问题 - 你不能对该目标进行单元测试,如果你想对代码进行单元测试,那么你必须创建一个库 link由工具和单元测试目标编辑(或在两个目标中包含文件)

根据@Cristik 的回答,真正归结为您的 Sources 文件夹中的内容。对我来说,我在 Sources 中有一个文件夹需要 完全 Tests 中的相同,只是需要 Tests 中的内容以 Tests 为后缀。所以,如果你有 Sources -> Foo-Bar,你必须有 Tests -> Foo-BarTests没有例外

另一个注意事项:所有破折号都将转换为下划线,因此您必须在测试文件的顶部添加 @testable import Foo_Bar

这似乎是因为我在您的模块目录中有一个 main.swift。这会生成一个可执行文件,而不是一个可以链接您的测试用例的库。

我通过将我的代码分成两个模块解决了这个问题。我有测试用例的库和仅包含 main.swift:

的应用程序
Package.swift
Sources\FooBarLib\
Sources\FooBarLib\Something.swift
Sources\FooBarLib\MoreStuff.swift
Sources\FooBarApp\main.swift
Tests\FooBarLibTests\TestSomething.swift

然后在我的 Package.swift 中确保 FooBarApp 依赖于 FooBarLib:

import PackageDescription

let package = Package(
    name: "FooBar",
    targets: [
        .target(name: "FooBarLib"),
        .target(name: "FooBarApp", dependencies: ["FooBarLib"])
    ],
)

然后在 TestSomething.swift 中导入 FooBarLib 模块:

@testable import FooBarLib
import XCTest

class TestSomething: XCTestCase {
    func testFunc() {
    }
}

在我的例子中,我通过在 Xcode 中显示测试导航器来启用测试,右键单击并启用测试。它奏效了。

在Swift4中,检查你的.testTarget是否依赖于FooBarLib

    .testTarget(
        name: "FooBarLibTests",
        dependencies: ["FooBarLib"]),

如果您在创建 pod 文件后添加 TestTarget。那么 pod 文件中可能缺少以下代码。

target 'DemoTests' do
  inherit! :search_paths
  # Pods for testing
end

在目标结束前添加上面的代码,如下所示。

target 'Demo' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for DocsDemo

  target 'DemoTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

在我的例子中,在将框架项目迁移到 link 其他框架(如 XCFramework 而不是通用框架)后,某些测试无法在 linking 步骤中编译。

我的修复是将那些失败的 objc 测试转换为 Swift,问题已解决。