是否可以在单元测试拆解中重置 dispatch_once 代码的状态?
我认为如果我们的单元测试可以从一个非常干净的状态运行会很好,但是我们正在努力处理 dispatch_once 和一些使用 dispatch once 制作的单例。
是否可以在单元测试拆解中重置 dispatch_once 代码的状态?
我认为如果我们的单元测试可以从一个非常干净的状态运行会很好,但是我们正在努力处理 dispatch_once 和一些使用 dispatch once 制作的单例。
我首先应该指出,除了测试之外,这在任何情况下都不是一件好事。即便如此,请谨慎行事——AliSoftware 在下面的评论中提供了一些细节和示例代码。另请参阅可以将谓词声明dispatch_once_t
为成员变量而不是静态的有趣答案吗?,包括马口中的一些重要信息。
dispatch_once_t
是一个typedef
d long
。它的 false 值为 0。如果将该标志重置为 0,dispatch_once()
将再次运行。您的问题是“只是”如何从另一个编译单元更改静态变量的值。为此,我认为您需要一个调试/单元测试挂钩,如下所示:
MakeWhoopie.h
#import <Foundation/Foundation.h>
void makeWhoopie(void);
#ifdef DEBUG
void resetDispatchOnce(void);
#endif
MakeWhoopie.m
#include "MakeWhoopie.h"
static dispatch_once_t * once_token_debug;
void makeWhoopie(void)
{
static dispatch_once_t once_token;
once_token_debug = &once_token; // Store address of once_token
// to access it in debug function.
dispatch_once(&once_token, ^{
NSLog(@"That's what you get, folks.");
});
NSLog(@"Making whoopie.");
}
#ifdef DEBUG
void resetDispatchOnce(void)
{
*once_token_debug = 0;
}
#endif
(您也可以once_token
向上移动到文件级别并直接更改它。)
试试这个:
#import <Foundation/Foundation.h>
#import "MakeWhoopie.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
makeWhoopie();
makeWhoopie();
resetDispatchOnce();
makeWhoopie();
}
return 0;
}
结果是:
2012-06-07 18:45:28.134 ResetDispatchOnce[8628:403] 这就是你得到的,伙计们。
2012-06-07 18:45:28.163 ResetDispatchOnce[8628:403] 大惊小怪。
2012-06-07 18:45:28.164 ResetDispatchOnce[8628:403] 大惊小怪。
2012-06-07 18:45:28.165 ResetDispatchOnce[8628:403] 这就是你得到的,伙计们。
2012-06-07 18:45:28.165 ResetDispatchOnce[8628:403] 大惊小怪。
我们也对我们的单例进行单元测试,偶尔需要用模拟对象替换它们或重置它们。我接受了乔希的回答并进一步简化了它:
static ArticleManager *_sharedInstance = nil;
static dispatch_once_t once_token = 0;
+(ArticleManager *)sharedInstance {
dispatch_once(&once_token, ^{
if (_sharedInstance == nil) {
_sharedInstance = [[ArticleManager alloc] init];
}
});
return _sharedInstance;
}
+(void)setSharedInstance:(ArticleManager *)instance {
if (instance == nil) once_token = 0;
_sharedInstance = instance;
}