为什么单元测试中的代码无法找到捆绑资源?
我正在单元测试的一些代码需要加载资源文件。它包含以下行:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
在应用程序中它运行得很好,但是当由单元测试框架 pathForResource:
运行时返回 nil,这意味着它无法找到 foo.txt
。
我已经确保 foo.txt
包含在单元测试目标的复制捆绑资源构建阶段中,那么为什么它找不到该文件呢?
Some code I am unit testing needs to load a resource file. It contains the following line:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
In the app it runs just fine, but when run by the unit testing framework pathForResource:
returns nil, meaning it could not locate foo.txt
.
I've made sure that foo.txt
is included in the Copy Bundle Resources build phase of the unit test target, so why can't it find the file?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
当单元测试工具运行您的代码时,您的单元测试包不是主包。
即使您正在运行测试,而不是您的应用程序,您的应用程序包仍然是主包。 (据推测,这可以防止您正在测试的代码搜索错误的包。)因此,如果您将资源文件添加到单元测试包中,则在搜索主包时将找不到它。如果将上面的行替换为:
那么您的代码将搜索单元测试类所在的包,一切都会好起来的。
When the unit test harness runs your code, your unit test bundle is NOT the main bundle.
Even though you are running tests, not your application, your application bundle is still the main bundle. (Presumably, this prevents the code you are testing from searching the wrong bundle.) Thus, if you add a resource file to the unit test bundle, you won't find it if search the main bundle. If you replace the above line with:
Then your code will search the bundle that your unit test class is in, and everything will be fine.
Swift 实现:
Swift 2
Swift 3、Swift 4
Bundle 提供了发现配置的主路径和测试路径的方法:
在 Xcode 6|7|8|9 中, 单元测试包路径将位于
Developer/Xcode/DerivedData
中,类似于......,与
Developer/CoreSimulator/Devices
分开code> 常规(非单元测试)捆绑路径:另请注意,默认情况下,单元测试可执行文件与应用程序代码链接。但是,单元测试代码应该仅在测试包中具有目标成员资格。应用程序代码应该仅在应用程序包中具有目标成员资格。在运行时,单元测试目标包注入到应用程序包中用于执行。
Swift Package Manager (SPM) 4:
注意:默认情况下,命令行
swift test
将创建一个MyProjectPackageTests .xctest
测试包。并且,swift 包generate-xcodeproj 将创建一个MyProjectTests.xctest 测试包。这些不同的测试包具有不同的路径。 此外,不同的测试包可能有一些内部目录结构和内容差异。在任何一种情况下,
.bundlePath
和.bundleURL
将返回当前在 macOS 上运行的测试包的路径。然而,Bundle
目前尚未在 Ubuntu Linux 上实现。此外,命令行 swift build 和 swift test 目前不提供复制资源的机制。
但是,通过一些努力,可以设置使用 Swift Package Manger 与 macOS Xcode、macOS 命令行和 Ubuntu 命令行环境中的资源的流程。可以在此处找到一个示例: 004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref< /a>
另请参阅:在单元中使用资源使用 Swift Package Manager 进行测试
Swift Package Manager (SwiftPM) 5.3+
Swift 5.3 包括 包管理器资源 SE-0271 演变提案,“状态:已实施 (Swift 5.3) ”。 :-)
示例
当前问题
Xcode
Bundle.module
由 SwiftPM 生成(请参阅 Build/BuildPlan.swift SwiftTargetBuildDescriptiongenerateResourceAccessor()),因此不是由 Xcode 构建时存在于 Foundation.Bundle 中。Xcode 将手动向模块添加一个
Resources
引用文件夹,添加 Xcode 构建阶段copy
将Resource
放入某个*.bundle
目录,并为 Xcode 构建添加一个#ifdef Xcode
编译器指令以使用资源。A Swift implementation:
Swift 2
Swift 3, Swift 4
Bundle provides ways to discover the main and test paths for your configuration:
In Xcode 6|7|8|9, a unit-test bundle path will be in
Developer/Xcode/DerivedData
something like ...... which is separate from the
Developer/CoreSimulator/Devices
regular (non-unit-test) bundle path:Also note the unit test executable is, by default, linked with the application code. However, the unit test code should only have Target Membership in just the test bundle. The application code should only have Target Membership in the application bundle. At runtime, the unit test target bundle is injected into the application bundle for execution.
Swift Package Manager (SPM) 4:
Note: By default, the command line
swift test
will create aMyProjectPackageTests.xctest
test bundle. And, theswift package generate-xcodeproj
will create aMyProjectTests.xctest
test bundle. These different test bundles have different paths. Also, the different test bundles may have some internal directory structure and content differences.In either case, the
.bundlePath
and.bundleURL
will return the path of test bundle currently being run on macOS. However,Bundle
is not currently implemented for Ubuntu Linux.Also, command line
swift build
andswift test
do not currently provide a mechanism for copying resources.However, with some effort, it is possible to set up processes for using the Swift Package Manger with resources in the macOS Xcode, macOS command line, and Ubuntu command line environments. One example can be found here: 004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref
See also: Use resources in unit tests with Swift Package Manager
Swift Package Manager (SwiftPM) 5.3+
Swift 5.3 includes Package Manager Resources SE-0271 evolution proposal with "Status: Implemented (Swift 5.3)". :-)
Example
Current Issue
Xcode
Bundle.module
is generated by SwiftPM (see Build/BuildPlan.swift SwiftTargetBuildDescription generateResourceAccessor()) and thus not present in Foundation.Bundle when built by Xcode.A comparable approach in Xcode would be to manually add a
Resources
reference folder to the module, add an Xcode build phasecopy
to put theResource
into some*.bundle
directory, and add a#ifdef Xcode
compiler directive for the Xcode build to work with the resources.在 Swift 3 中,语法
self.dynamicType
已被弃用,请改用此语法或
With swift Swift 3 the syntax
self.dynamicType
has been deprecated, use this insteador
确认资源已添加到测试目标。
Confirm that the resource is added to the test target.
如果您的项目中有多个目标,那么您需要在目标成员资格中可用的不同目标之间添加资源,并且可能需要在不同的目标之间切换,如 3 个步骤所示下图
if you have multiple target in your project then you need to add resources between different target available in the Target Membership and you may need to switch between different Target as 3 steps shown in the figure below
我必须确保设置此常规测试复选框
I had to ensure this General Testing checkbox was set
对于像我这样的人来说,在原始帖子中错过了这一点:
确保 foo.md 包含在单元测试目标的复制捆绑资源构建阶段
Just for people like me, that missed this point in the original post:
Make sure that foo.md is included in the Copy Bundle Resources build phase of the unit test target
有一段代码可以在以下位置找到该文件:
如何检查文件是否存在存在于 Swift 的 Documents 目录中吗?
我在测试中使用了它,如下所示,该测试测试我的文件是否已创建并给出其位置以供进一步测试。
这并不是测试文件是否在正确的位置创建,而是测试文件是否已创建。
There is a code which finds the file in :
How to check if a file exists in the Documents directory in Swift?
I used it in a test as follows, which tests that my file is created and gives its location for further testing.
This is not testing that the file is created in the right place, only that it is created.