gpt4 book ai didi

ios - 单元测试单例 : mock and swizzle

转载 作者:行者123 更新时间:2023-12-01 16:34:17 26 4
gpt4 key购买 nike

我目前正在尝试测试一些使用 AVAudioSession 的代码,并且我尝试模拟它,因为它是一个单例,到目前为止证明是困难的,我做了一些研究并想到了这个想法调配它的方式是它的实例,然后按照您的意愿实际初始化您的子类,但我无法弄清楚要调配的方法。我尝试了 sharedInstance 并且 class_addMethod() 返回 yes 表示它已添加而不是替换它。我可以通过这种方式有效地模拟单例吗?

@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

最佳答案

你可以调整 sharedInstance 方法来返回你的 AVAudioSessionFake 就像这样

#AVAudioSessionFake:

@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

#调配共享实例:

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;
}

#使用:

- (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-C , method swizzling , another question in SO

关于ios - 单元测试单例 : mock and swizzle,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29689282/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com