ios NSURL 到 XCTest 测试包中的文件路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19309092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
NSURL to file path in test bundle with XCTest
提问by Eduardo Arenas Prada
I am trying to write an iOS app using TDD and the new XCTest framework. One of my methods retrieves a file from the internet (given a NSURL object) and stores it in the user's documents. The signature of the method is similar to:
我正在尝试使用 TDD 和新的 XCTest 框架编写一个 iOS 应用程序。我的一种方法从 Internet 检索文件(给定一个 NSURL 对象)并将其存储在用户的文档中。该方法的签名类似于:
- (void) fetchAndStoreImage:(NSURL *)imageUrl
I'm trying to write the test for this method in a way that it doesn't fail if there is no connection to the internet. My approach (taken from a previous question) is to call the method using a NSURL to an image in the local file system.
我正在尝试以一种在没有连接到 Internet 的情况下不会失败的方式编写此方法的测试。我的方法(取自上一个问题)是使用 NSURL 调用本地文件系统中的图像的方法。
When a new project with unit tests enabled is created, the Tests directory has a subdirectory named 'Supporting Files'. I suppose that is where my test images should go. My question is how can I get a NSURL object that points to an image in this directory, as I wouldn't want test images to be bundled with the application. Any help is appreciated.
创建启用了单元测试的新项目时,Tests 目录有一个名为“Supporting Files”的子目录。我想这就是我的测试图像应该去的地方。我的问题是如何获得指向此目录中图像的 NSURL 对象,因为我不希望测试图像与应用程序捆绑在一起。任何帮助表示赞赏。
回答by Ben Clayton
In fact, the [NSBundle mainBundle]
when running a UnitTest is notthe path of your app, but is /Developer/usr/bin, so this will not work.
实际上,[NSBundle mainBundle]
运行UnitTest时的路径不是您的应用程序的路径,而是/Developer/usr/bin,因此这是行不通的。
The way to get resources in a unit test is here: OCUnit & NSBundle
在单元测试中获取资源的方法在这里:OCUnit & NSBundle
In short, use:
简而言之,使用:
[[NSBundle bundleForClass:[self class]] resourcePath]
or in your case:
或者在你的情况下:
[[NSBundle bundleForClass:[self class]] resourceURL]
回答by l --marc l
Swift 5.3
斯威夫特 5.3
Note: Swift 5.3 includes Package Manager Resources SE-0271capabilities which can be used with application bundle and test bundle resources.
注意:Swift 5.3 包含包管理器资源 SE-0271功能,可与应用程序包和测试包资源一起使用。
Resources aren't always intended for use by clients of the package; one use of resources might include test fixtures that are only needed by unit tests. Such resources would not be incorporated into clients of the package along with the library code, but would only be used while running the package's tests.
资源并不总是供包的客户使用;资源的一种用途可能包括仅单元测试需要的测试装置。此类资源不会与库代码一起合并到包的客户端中,而只会在运行包的测试时使用。
Swift 4, 5:
斯威夫特 4、5:
let testBundle = Bundle(for: type(of: self))
guard let fileURL = testBundle.url(forResource: "imageName", withExtension: "png")
else { fatalError() }
// path approach
guard let filePath = bundle.path(forResource: "dataName", ofType: "csv")
else { fatalError() }
let fileUrl = URL(fileURLWithPath: filePath)
Bundle provides ways to discover the main and test paths for your configuration:
Bundle 提供了发现配置的主要路径和测试路径的方法:
@testable
import Example
class ExampleTests: XCTestCase {
func testExample() {
let bundleMain = Bundle.main
let bundleDoingTest = Bundle(for: type(of: self ))
let bundleBeingTested = Bundle(identifier: "com.example.Example")!
print("bundleMain.bundlePath : \(bundleMain.bundlePath)")
// …/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents
print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)")
// …/PATH/TO/Debug/ExampleTests.xctest
print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)")
// …/PATH/TO/Debug/Example.app
print("bundleMain = " + bundleMain.description) // Xcode Test Agent
print("bundleDoingTest = " + bundleDoingTest.description) // Test Case Bundle
print("bundleUnderTest = " + bundleBeingTested.description) // App Bundle
The Xcode URL will be in Developer/Xcode/DerivedData
something like ...
Xcode URL 将Developer/Xcode/DerivedData
类似于...
file:///Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
imageName.png
... which is separate from Developer/CoreSimulator/Devices
URL
...与Developer/CoreSimulator/Devices
URL分开
file:///Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
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.
另请注意,默认情况下,单元测试可执行文件与应用程序代码链接。但是,单元测试代码应该只在测试包中具有 Target Membership。应用程序代码在应用程序包中应该只具有目标成员资格。在运行时,单元测试目标包被注入到应用程序包中执行。
Swift Package Manager (SPM) 4:
Swift 包管理器 (SPM) 4:
let testBundle = Bundle(for: type(of: self))
print("testBundle.bundlePath = \(testBundle.bundlePath) ")
Note: By default, the command line swift test
will create a MyProjectPackageTests.xctest
test bundle. And, the swift package generate-xcodeproj
will create a MyProjectTests.xctest
test bundle. These different test bundles have different paths. Also, the different test bundles may have some internal directory structure and content differences.
注意:默认情况下,命令行将swift test
创建一个MyProjectPackageTests.xctest
测试包。并且,swift package generate-xcodeproj
将创建一个MyProjectTests.xctest
测试包。这些不同的测试包有不同的路径。此外,不同的测试包可能有一些内部目录结构和内容差异。
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.
在任何一种情况下,.bundlePath
和.bundleURL
都将返回当前在 macOS 上运行的测试包的路径。但是,Bundle
目前尚未为 Ubuntu 实现。
Also, command line swift build
and swift test
do not currently provide a mechanism for copying resources.
此外,命令行swift build
和swift test
当前不提供复制资源的机制。
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
但是,通过一些努力,可以在 macOS Xcode、macOS 命令行和 Ubuntu 命令行环境中设置使用 Swift Package Manger 和资源的过程。可以在此处找到一个示例:004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref
回答by Denis Kutlubaev
Just to append to correct answer, this is example how to get filePath for a file in your UnitTests/Supporting Files:
只是为了附加到正确的答案,这是如何在您的单元测试/支持文件中获取文件的文件路径的示例:
NSString *filePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"YourFileName.json"];
XCTAssertNotNil(filePath);
This probably will be useful for someone.
这可能对某人有用。
回答by bpds
- You can reference bundle files like in any target.
- Check if the file is Copyed in the Copy Bundle Resources build phase (of your test target)
To access to the local file :
NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
- 您可以像在任何目标中一样引用捆绑文件。
- 检查文件是否在 Copy Bundle Resources 构建阶段(您的测试目标)被复制
访问本地文件:
NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
You can make asynchronous access and wait for the response using : https://github.com/travisjeffery/TRVSMonitor
您可以使用以下方法进行异步访问并等待响应:https: //github.com/travisjeffery/TRVSMonitor
If you have added : dataset1.json
in the test target (2) :
如果您已添加 :dataset1.json
在测试目标 (2) 中:
NSString *p=[[NSBundle mainBundle] pathForResource:@"dataset1" ofType:@"json"];
NSLog(@"%@",p);
2013-10-29 15:49:30.547 PlayerSample[13771:70b] WT(0): /Users/bpds/Library/Application Support/iPhone Simulator/7.0/Applications/7F78780B-684A-40E0-AA35-A3B5D8AA9DBD/PlayerSample.app.app/dataset1.json
2013-10-29 15:49:30.547 PlayerSample[13771:70b] WT(0):/Users/bpds/Library/Application Support/iPhone Simulator/7.0/Applications/7F78780B-684A-40E0-AAD35-AASPAD9B5 app.app/dataset1.json
回答by superarts.org
Swift
version based on accepted answer:
Swift
基于接受答案的版本:
let url = URL(fileURLWithPath: Bundle(for: type(of: self)).path(forResource: "my", ofType: "json") ?? "TODO: Proper checking for file")
回答by odyth
The problem I was facing was that application code was trying to access the main bundle for things like bundleIdentifier and since the main bundle wasn't my unit test project it would return nil.
我面临的问题是应用程序代码试图访问主包以获取诸如 bundleIdentifier 之类的东西,并且由于主包不是我的单元测试项目,它会返回 nil。
A hack around this that works in both Swift 3.0.1 and Objective-C is to create an Objective-C category on NSBundle and include it in your unit test project. You don't need a bridging header or anything. This category will get loaded and now when you application code asks for the main bundle your category will return the unit test bundle.
在 Swift 3.0.1 和 Objective-C 中都可以使用的解决方法是在 NSBundle 上创建一个 Objective-C 类别并将其包含在您的单元测试项目中。您不需要桥接头或任何东西。此类别将被加载,现在当您的应用程序代码要求主包时,您的类别将返回单元测试包。
@interface NSBundle (MainBundle)
+(NSBundle *)mainBundle;
@end
@implementation NSBundle (Main)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+(NSBundle *)mainBundle
{
return [NSBundle bundleForClass:[SomeUnitTest class]];
}
#pragma clang diagnostic pop
@end
回答by Dan Rosenstark
Here's the Swift version of this, Xcode 7, iOS 9, etc.
这是 Swift 版本,Xcode 7、iOS 9 等。
let testBundle = NSBundle(forClass: self.dynamicType)
let path = testBundle.pathForResource("someImage", ofType: "jpg")
XCTAssertNotNil(path)
Note: someImage.jpg must be included in your test target.
注意: someImage.jpg 必须包含在您的测试目标中。
Edit: Swift 5
编辑:斯威夫特 5
let testBundle = Bundle(for: type(of: self))
let path = testBundle.path(forResource: "someImage", ofType: "jpg")
XCTAssertNotNil(path)