Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSImage from Asset Catalog in Test Target

My unit tests target needs to load an image resource for use in some of the tests, but I am having trouble loading it.

  1. I have created an asset catalog within the test target.
  2. I have added a new image set resource to the catalog, checked the "Mac" box in "Devices", and set its source images for both resolutions (@1x and @2x):

enter image description here

  1. I have checked the "copy bundle resource" build phase of the test target, and it does include the asset catalog.

  2. 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...

like image 392
Nicolas Miari Avatar asked Mar 22 '18 05:03

Nicolas Miari


People also ask

What is an asset catalog?

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.

What is asset catalog in Swift?

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.

What is asset catalog Xcode?

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.


1 Answers

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.

like image 179
Dr. F. Avatar answered Oct 07 '22 02:10

Dr. F.