首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单例单元测试: mock和swizzle

单例单元测试: mock和swizzle
EN

Stack Overflow用户
提问于 2015-04-17 10:37:09
回答 1查看 1.7K关注 0票数 3

我目前正在尝试测试一些使用AVAudioSession的代码,由于它是一个单例,我试图模拟它的尝试到目前为止已经被证明是困难的,我做了一些研究,突然想到了一个想法,让它获得它的实例,然后按照你想要的方式实际初始化你的子类,但是我很难弄清楚应该用什么方法。我尝试了sharedInstance,class_addMethod()返回yes,说明它是添加的,而不是替换的。我能用这种方式有效地模拟一个单例吗?

代码语言:javascript
复制
@interface AVAudioSessionFake : AVAudioSession

@property (readonly,    nonatomic) BOOL wasSetActiveErrorCalled;

-(instancetype)initStub;

@end

@implementation AVAudioSessionFake

+ (void)load
{
    [AVAudioSessionFake swizzleOriginalMethod:@"sharedInstance" with:@"initStub"];
}

+ (void)swizzleOriginalMethod:(NSString*)Original with:(NSString*)replacement
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        Class class = [self class];

        SEL originalSelector = NSSelectorFromString(Original);
        SEL swizzledSelector = NSSelectorFromString(replacement);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                      originalSelector,
                      method_getImplementation(swizzledMethod),
                      method_getTypeEncoding(swizzledMethod));

        if (didAddMethod)
        {
          class_replaceMethod(class,
                              swizzledSelector,
                              method_getImplementation(originalMethod),
                              method_getTypeEncoding(originalMethod));
        }
        else
        {
          method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

-(instancetype)initStub
{
    return [[[self class]alloc]init];
}

- (BOOL)setActive:(BOOL)active error:(NSError *__autoreleasing *)outError
{
    _wasSetActiveErrorCalled = YES;

    return [super setActive:active error:outError];
}

@end
EN

回答 1

Stack Overflow用户

发布于 2015-04-20 12:58:43

您可以使用sharedInstance方法返回您的AVAudioSessionFake,如下所示

#AVAudioSessionFake:

代码语言:javascript
复制
@interface AVAudioSessionFake : AVAudioSession
@property (readonly,    nonatomic) BOOL wasSetActiveErrorCalled;

@end

@implementation AVAudioSessionFake
-(instancetype)init
{
    if (self == [super init]) {
        // your init code
    }
    return self;
}
 -(BOOL)setActive:(BOOL)active error:(NSError *__autoreleasing *)outError
{
     _wasSetActiveErrorCalled = YES;

    return [super setActive:active error:outError];
}
@end

# swizzle sharedInstance:

代码语言:javascript
复制
static Method original_AVAudioSession_SharedInstance_ClassMethod;
static Method swizzled_AVAudioSession_SharedInstance_ClassMethod;
@interface AVAudioSession (AVAudioSessionSwizzledSharedInstance) 
@end
@implementation AVAudioSession (AVAudioSessionSwizzledSharedInstance)
    + (void)load
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^
        {
          Class class = object_getClass((id)self);
          SEL original_Selector = @selector(sharedInstance);
          SEL swizzled_Selector = @selector(swizzled_sharedInstance);
          original_AVAudioSession_SharedInstance_ClassMethod = class_getInstanceMethod(class, original_Selector);
          swizzled_AVAudioSession_SharedInstance_ClassMethod = class_getInstanceMethod(class, swizzled_Selector);
        });
    }
    + (void)swizzling_AVAudioSession_SharedInstance
    {    
    method_exchangeImplementations(original_AVAudioSession_SharedInstance_ClassMethod,swizzled_AVAudioSession_SharedInstance_ClassMethod);
    }
    + (id)swizzled_sharedInstance 
    {
         static dispatch_once_t p = 0;
        // initialize sharedObject as nil (first call only)
        __strong static AVAudioSessionFake _sharedObject = nil;

        dispatch_once(&p, ^{
            _sharedObject = [[AVAudioSessionFake alloc] init];
        });
        return _sharedObject;
    }

#使用:

代码语言:javascript
复制
- (void)testAnAVAudioSessionMethod {
   [AVAudioSession swizzling_AVAudioSession_SharedInstance]; //Start swizzling shareInstance method
   // some test code and assert result here
   [AVAudioSession swizzling_AVAudioSession_SharedInstance]; //return original method
}

一些有用的链接The Right Way to Swizzle in Objective-Cmethod swizzlinganother question in SO

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29689282

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档