如何将 XCTestCases 暴露给外部测试包?

Posted

技术标签:

【中文标题】如何将 XCTestCases 暴露给外部测试包?【英文标题】:How to expose XCTestCases to external test bundles? 【发布时间】:2016-07-09 02:34:10 【问题描述】:

我有一个框架Whiteboard,它封装了我的业务逻辑。我试图保持我的依赖倒置和解耦,因此由于Whiteboard 依赖于存储库,它声明了一个协议WhiteboardRepository,并且它希望链接到Whiteboard 的客户端提供WhiteboardRepository 的实现。

您可以在下面的屏幕截图中看到这一点。还要注意WhiteboardTests 组,其中包括WhiteboardRepositoryTests 类以及WhiteboardRepositoryFake 及其自己的测试子类。

为确保WhiteboardRepository 的实现按预期运行,WhiteboardTests 测试包定义了XCTestCaseWhiteboardRepositoryTests 子类:

class WhiteboardRepositoryTests: XCTestCase 
  var repo: WhiteboardRepository?

  override func setUp() 
    if let repo = repo 
      // test setup here
    
  

  // test cases here


为了让Whiteboard 的客户端测试其对WhiteboardRepository 的实现,实现的测试类将WhiteboardRepositoryTests 子类化,并将实现的实例提供给测试子类,然后它在以下情况下使用该实例运行测试。

例如,WhiteboardRepositoryFakeTests 是这样的:

class WhiteboardRepositoryFakeTests: WhiteboardRepositoryTests 
    override func setUp() 
        repo = WhiteboardRepositoryFake()
        super.setUp()
    

    // the test classes run, using the instance of WhiteboardRepositoryFake()

这当然可以,因为WhiteboardRepositoryFakeTestsWhiteboardTests 包中,所以WhiteboardRepositoryTests 暴露给WhiteboardRepositoryFakeTests

问题是:链接到 Whiteboard 的应用程序需要创建自己的 WhiteboardRepositoryTests 子类来测试自己的实现,但因为它们无权访问 WhiteboardTests 测试包,所以它们是不知道 WhiteboardRepositoryTests 类,因此不能对其进行子类化。

我有多个使用 Whiteboard 的客户端,所以我不能简单地将 WhiteboardRepositoryTests 类复制到每个客户端中——我也不想这样做,因为定义 WhiteboardRepositoryWhiteboard 的责任的行为,所以WhiteboardRepositoryTests 应该存在于Whiteboard 的测试包中。在理想情况下,我可以将Whiteboard 的测试包链接或注入到客户端的测试包中,以便WhiteboardRepositoryTests 暴露于客户端的测试中,但我不知道该怎么做。

有没有办法绕过这个障碍?如何将 WhiteboardRepositoryTests 公开给客户端测试包中的测试,以便客户端可以确保其对 WhiteboardRepository 的实现按预期运行?

【问题讨论】:

【参考方案1】:

这里的主要问题是 WhiteboardTests 目标很可能是一个测试目标,实际上并没有构建可链接的框架。这会阻止我们构建另一个目标(您的客户端测试),从它导入和子类化。例如,您会注意到测试目标缺少用于从框架导出符号的正常 TARGET_NAME.h 头文件。我们需要的是一个构建框架但与 XCTest 链接的目标。客户项目的测试目标将与此框架链接,以导入和子类化它提供的 XCTestCase 类。那么该怎么办:

    通过单击项目文件,然后单击编辑器 > 添加目标,在白板项目中创建框架构建目标。我们暂时称它为 WhiteboardAbstractTests。此目标将与 XCTest 链接并构建一个框架,以提供您希望客户项目的测试子类化的超类。

    现在,与 XCTest 链接有点奇怪,因为它们不再使其在 Xcode 中可用。但是,您仍然可以在 Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Frameworks/XCTest.framework 找到 XCTest 框架并将其拖到 Xcode 中的 WhiteboardAbstractTests 目标文件夹中。

    从这里开始,您应该能够在 WhiteboardAbstractTests 中定义 XCTestCase 子类,这些子类将内置到 WhiteboardAbstractTests.framework 中。

    在您的客户端项目中,我假设 Whiteboard xcodeproj 以某种方式嵌套在 Cocoapods、Carthage 或 git 子模块中。找到 Whiteboard xcodeproj 文件并将其拖到 Xcode 中的客户端项目测试目标中。

    在 Xcode 中选择客户端项目文件并转到 Build Phases。在目标依赖项下,单击加号按钮,您应该会看到来自 Whiteboard 的各种构建目标。选择 WhiteboardAbstractTests。这将确保 Xcode 在构建客户端测试之前构建抽象测试。

    同样在 Build Phases 中,在 Link Binary With Libraries 下,选择 WhiteboardAbstractTests 以确保我们的测试目标与 Whiteboard 提供的抽象测试链接并可以从其中导入类。

从这里您应该能够在您的客户端项目中运行测试,该项目将构建 WhiteboardAbstractTests,将您的客户端测试与它链接,并运行您的客户端测试,这些测试是抽象测试的子类。我已经快速测试过了,如果您遇到问题,请告诉我。

附:我喜欢你的建筑风格。 Martin Fowler 在某处流下了喜悦的泪水。

【讨论】:

这听起来是个好主意,但是当我尝试时,我得到了Cannot load underlying module for 'XCTest'。当我尝试将#import <XCTest/XCTest.h> 添加到桥接头时,“加载模块”错误消失了,但我在桥接头中收到了'XCTest/XCTest.h' file not found 错误,这尤其令人困惑,因为XCTest.h 就在我拖动的框架中在。 等一下,我想也许我明白了——至少是第一部分。我不得不将XCTest 框架复制到我的项目中,并添加到框架搜索路径中以直接指向磁盘上的它。然后我必须将 Whiteboard 框架链接到 WhiteboardContractTests,最后,我必须将测试文件目标成员资格授予 WhiteboardTests 测试包。我现在就去尝试让客户端工作。 啊,是的,我对 XCTest 不是很清楚,但我想你已经明白了。 与其复制 XCTest.framework,不如将 $PLATFORM_DIR/Developer/Library/Frameworks 添加到测试框架目标的“框架搜索路径”构建设置中。这应该允许您导入 XCTest 而无需任何进一步的恶作剧。

以上是关于如何将 XCTestCases 暴露给外部测试包?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有端口映射的情况下将 docker 容器的 ip 和端口暴露给外部 docker 主机?

K8S 之 将服务暴露给外部客户端

将变量从main.js暴露给vue-cli项目中的其他脚本

使用 XCTestCases 类中的可访问性标识符访问 NavigationLink - SwiftUI

除了实例化 DAL 的 BLL 之外,还有啥选项允许在 n 层解决方案中进行单元测试,而不会将 DAL 暴露给 UI 或将 BLL 暴露给 DAL?

如何让不同的 Docker 容器相互通信而不将端口暴露给全世界