My unit tests target needs to load an image resource for use in some of the tests, but I am having trouble loading it.
I have checked the "copy bundle resource" build phase of the test target, and it does include the asset catalog.
I have checked the target membership of the asset catalog and image set, and it is indeed the test target.
When running the tests, I am attempting to load the image using code like below:
guard let image = NSImage(named: NSImage.Name("TestSourceImage")) else {
fatalError("Test Resource is Missing.")
}
...but the guard fails.
I also tried:
let bundle = Bundle(for: MyClassTests.self)
guard let path = bundle.pathForImageResource(NSImage.Name("TestSourceImage")) else {
fatalError("Test Resource is Missing.")
}
guard let image = NSImage(contentsOfFile: path) else {
fatalError("Test Resource File is Corrupt.")
}
...but the first guard fails (can't retrieve the resource path).
I have tried both formats
NSImage.Name("TestSourceImage")
and:
NSImage.Name(rawValue: "TestSourceImage")
I have also tried Bundle.urlForImageResource(_)
, but it fails too.
I have seen similar questions and answers, but they either apply to iOS or to resources in the app (main) bundle.
What am I missing?
UPDATE:
In the meantine, I've worked around the problem by adding my test image as a stand-alone image resource (not using asset catalogs), and loading it with the following code:
let bundle = Bundle(for: MyClassTests.self)
guard let url = bundle.url(forResource: "TestSourceImage", withExtension: "png") else {
fatalError("!!!")
}
guard let image = NSImage(contentsOf: url) else {
fatalError("!!!")
}
I don't need to support multiple resolutions in this case (my image is the source for an image processing algorithm; it is already assumed to be at the highest resolution necessary), and even if I did, I would just switch from .png to .tiff, I guess.
The problem seems to be that, NSImage
does not have an initializer analogous to UIImage
's init(named:in:compatibleWith:)
, which lets you specify the bundle from which to load the image (second argument).
You can instead ask a specific bundle (other than main
) to create a resource URL and instantiate the image from that (like I did above), but this isn't compatible with asset catalogs it seems. Further information is welcome...
There is an extension on Bundle that allows to load a named image from an asset catalog:
extension Bundle {
@available(OSX 10.7, *)
open func image(forResource name: NSImage.Name) -> NSImage?
}
Referring to your example, you may use the following in an XCTestCase to access the image (Swift 5):
guard let image = Bundle(for: type(of: self)).image(forResource: "TestSourceImage") else {
fatalError("Test Resource is Missing.")
}
Tested on macOS 10.14.