可以在单元测试中重置dispatch_once的状态,使它们再次运行

And*_*ndi 32 objective-c grand-central-dispatch

是否可以在单元测试tearDown中重置dispatch_once代码的状态?

我认为如果我们的单元测试可以从一个非常干净的状态运行会很好,但我们正在努力使用dispatch_once和一些使用dispatch进行的单例测试.

Jos*_*ell 44

我首先要注意的是,除了测试之外,在任何情况下这都不是一件好事; 即便如此,请小心处理 - AliSoftware在下面的评论中提供了一些细节和示例代码.另请参阅有趣的答案我可以将dispatch_once_t谓词声明为成员变量而不是静态吗?,包括马口的一些重要信息.

dispatch_once_t是一个typedefd long.其false值为0.如果将该标志重置为0,dispatch_once()则会再次运行.您的问题是"只是"如何从另一个编译单元更改静态变量的值.为此,我认为你需要一个调试/单元测试钩子,如下所示:

MakeWhoopie.h

#import <Foundation/Foundation.h>

void makeWhoopie(void);

#ifdef DEBUG
void resetDispatchOnce(void);
#endif
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

(您也可以once_token升级到文件级别并直接更改它.)

尝试这个:

#import <Foundation/Foundation.h>
#import "MakeWhoopie.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        makeWhoopie();
        makeWhoopie();
        resetDispatchOnce();
        makeWhoopie();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

2012-06-07 18:45:28.134 ResetDispatchOnce [8628:403]这就是你得到的,伙计们.
2012-06-07 18:45:28.163 ResetDispatchOnce [8628:403]制作whoopie.
2012-06-07 18:45:28.164 ResetDispatchOnce [8628:403]制作whoopie.
2012-06-07 18:45:28.165 ResetDispatchOnce [8628:403]这就是你得到的,伙计们.
2012-06-07 18:45:28.165 ResetDispatchOnce [8628:403]制作whoopie.

  • 请参阅https://gist.github.com/AliSoftware/6935128,以获取一些长异步代码(即使在测试后仍然可以运行`tearDown`)也可能产生潜在风险的示例.当然我同意(1)这是不太可能的,并且(2)这是错误的编程,用户应该修复其单元测试以检查在完成块被调用时测试是否超时.但新手仍然可以遇到这种棘手的情况,所以恕我直言,对于不习惯并发细微之处的用户来说,值得警告,让他们知道这是谨慎使用的,只有在特定情况下才能使用. (2认同)