Accessing a UIImage inside a OCUnit test target
Asked Answered
B

4

13

I'm currently writing an image manipulation test for an iPad app. I have a resources folder inside my unit test target with a photo inside, however when I try to access it using [UIImage imageNamed:@"photo1.jpg"] no image gets returned. If I change the file name to one in the main Resources folder an image does get returned.

Is there a way to access the Resources folder inside the unit test target?

Biggerstaff answered 22/12, 2011 at 10:59 Comment(0)
B
25

Found the answer to this, looks like you can't use [UIImage imageNamed:], you can access the image like this:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *imagePath = [bundle pathForResource:@"photo1" ofType:@"jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
Biggerstaff answered 23/12, 2011 at 9:12 Comment(0)
T
13

Since iOS 8 we have the: -imageNamed:inBundle:compatibleWithTraitCollection: failable init on UIImage

In Swift:

let bundle = NSBundle(forClass: self.dynamicType)
let image:UIImage? = UIImage(named: "imageFileName",
                          inBundle:bundle,
     compatibleWithTraitCollection:nil)

In Objective-C

NSBundle* bundle = [NSBundle bundleForClass:[self class]];
UIImage* image = [UIImage imageNamed:@"imageFileName.extension"
                             inBundle:bundle
        compatibleWithTraitCollection:nil];

Documentation

Teerell answered 30/7, 2014 at 23:35 Comment(1)
This answer should be at the top. I've created a new initialiser for UIImage to do just what this already does. I feel kind of dumb right now. gist.github.com/Psidium/6d15525d4fba7b191290Paroxysm
M
3

Made a handy category for this.

image = [UIImage testImageNamed:@"image.png"];

Goes like:

@interface BundleLocator : NSObject
@end

@interface UIImage (Test)
+(UIImage*)testImageNamed:(NSString*) imageName;
@end

@implementation BundleLocator
@end

@implementation UIImage (Test)
+(UIImage*)testImageNamed:(NSString*) imageName
{
    NSBundle *bundle = [NSBundle bundleForClass:[BundleLocator class]];
    NSString *imagePath = [bundle pathForResource:imageName.stringByDeletingPathExtension ofType:imageName.pathExtension];
    return [UIImage imageWithContentsOfFile:imagePath];
}
@end
Malevolent answered 6/5, 2014 at 23:45 Comment(0)
M
2

You can use the following category (but add it only to test target!). It will make UIImage imageNamed: method work automatically in test target:

.h file

/**
 * UIImage imageNamed: method does not work in unit test
 * This category provides workaround that works just like imageNamed method from UIImage class.
 * Works only for png files. If you need other extension, use imageNamed:extension: method.
 * NOTE: Do not load this category or use methods defined in it in targets other than unit tests
 * as it will replace original imageNamed: method from UIImage class!
 */
@interface UIImage (ImageNamedForTests)

/**
 * Returns image with the specified name and extension.
 * @param imageName Name of the image file. Should not contain extension.
 * NOTE: You do not have to specify '@2x' in the filename for retina files - it is done automatically.
 * @param extension Extension for the image file. Should not contain dot.
 * @return UIImage instance or nil if the image with specified name and extension can not be found.
 */
+ (UIImage *)imageNamed:(NSString *)imageName extension:(NSString *)extension;


@end

.m file

#import "UIImage+ImageNamedForTests.h"
#import <objc/runtime.h>

@implementation UIImage (ImageNamedForTests)

+ (void)load {
    [self swizzleClassMethod];
}

+ (void)swizzleClassMethod {
    SEL originalSelector = @selector(imageNamed:);
    SEL newSelector = @selector(swizzled_imageNamed:);
    Method origMethod = class_getClassMethod([UIImage class], originalSelector);
    Method newMethod = class_getClassMethod([UIImage class], newSelector);
    Class class = object_getClass([UIImage class]);
    if (class_addMethod(class, originalSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
        class_replaceMethod(class, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    } else {
        method_exchangeImplementations(origMethod, newMethod);
    }
}

+ (UIImage *)swizzled_imageNamed:(NSString *)imageName {
    return [self imageNamed:imageName extension:@"png"];
}

+ (UIImage *)imageNamed:(NSString *)imageName extension:(NSString *)extension {
    NSBundle *bundle = [NSBundle bundleForClass:[SomeClassFromUnitTestTarget class]];//Any class from test bundle can be used. NOTE: Do not use UIImage, as it is from different bundle
    NSString *imagePath = [bundle pathForResource:imageName ofType:extension];
    return [UIImage imageWithContentsOfFile:imagePath];
}
Monostylous answered 6/12, 2013 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.