Подтвердить что ты не робот

Возможно reset состояние dispatch_once в unit test, чтобы они снова запускались

Возможно ли reset состояние кода dispatch_once в unit test tearDown?

Я думаю, было бы неплохо, если бы наши юнит-тесты могли работать из действительно чистого состояния, но мы боремся с dispatch_once и некоторыми синглтонами, сделанными с отправкой один раз.

4b9b3361

Ответ 1

Прежде всего, я должен отметить, что это нехорошо делать в любой ситуации, кроме тестирования; даже тогда, продолжайте с осторожностью - AliSoftware предоставляет некоторые детали и пример кода в комментариях ниже. См. Также интересные ответы в Могу ли я объявить предикат dispatch_once_t как переменную-член вместо статики?, включая важную информацию от устья лошади.

dispatch_once_t является typedef d long. Его ложное значение равно 0. Если вы reset, флаг которого равен 0, dispatch_once() снова запустится. Ваша проблема "просто", как изменить значение статической переменной из другого модуля компиляции. Для этого я думаю, что вам нужен отладочный /unit test hook, например:

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 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] Создание 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] Создание воинственности.

Ответ 2

Мы тоже unit test наши синглтоны и иногда должны заменять их макетными объектами или reset их. Я ответил Джошу и немного упростил его:

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