访问 OCUnit 测试目标中的 UIImage

Posted

技术标签:

【中文标题】访问 OCUnit 测试目标中的 UIImage【英文标题】:Accessing a UIImage inside a OCUnit test target 【发布时间】:2011-12-22 10:59:50 【问题描述】:

我目前正在为 iPad 应用程序编写图像处理测试。我的单元测试目标中有一个资源文件夹,里面有一张照片,但是当我尝试使用 [UIImage imageNamed:@"photo1.jpg"] 访问它时,没有返回图像。如果我将文件名更改为主资源文件夹中的一个,则会返回图像。

有没有办法访问单元测试目标中的 Resources 文件夹?

【问题讨论】:

【参考方案1】:

找到了这个问题的答案,貌似不能用[UIImage imageNamed:],可以这样访问图片:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *imagePath = [bundle pathForResource:@"photo1" ofType:@"jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];

【讨论】:

【参考方案2】:

ios 8 开始,我们有:-imageNamed:inBundle:compatibleWithTraitCollection: UIImage 上的失败初始化

在 Swift 中:

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

在 Objective-C 中

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

Documentation

【讨论】:

这个答案应该在顶部。我已经为 UIImage 创建了一个新的初始化程序来完成它已经完成的工作。我现在感觉有点傻。 gist.github.com/Psidium/6d15525d4fba7b191290【参考方案3】:

为此做了一个方便的分类。

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

类似:

@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

【讨论】:

【参考方案4】:

您可以使用以下类别(但仅将其添加到测试目标!)。它将使 UIImage imageNamed: 方法在测试目标中自动工作:

.h 文件

/**
 * 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 文件

#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];

【讨论】:

以上是关于访问 OCUnit 测试目标中的 UIImage的主要内容,如果未能解决你的问题,请参考以下文章

UINavigationController 中的 OCUnit 测试问题

为 iOS 构建 OCUnit 应用程序测试目标时出现链接器错误

如何在单元测试(OCUnit)中访问 NSDocumentDirectory

什么是开始使用 OCUnit 进行 iPhone 单元测试的好教程?

GHUnit 作为测试包而不是单独的目标

OCUnit 在私有财产上