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...
Asset catalogs simplify access to app resources by mapping between named assets and one or more files targeted for different device attributes. Attributes include device characteristics, size classes, on-demand resources, and type-specific information.
Asset catalogs help you quickly organize and manage your app's resources. In an asset catalog, each asset set represents one resource — like an image, color, or data file — that your app loads at runtime.
An asset catalog, simply put, is a single folder in Xcode that you use to organize your app's images, icons, colors, and more. Instead of adding individual images to Xcode's file organizer, you add assets neatly organized in a single catalog.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With