Изменить системную дату для Cocoa модульного тестирования

Я тестирую метод, который вызывает -[NSDate date], и использует системное время в качестве ссылки для выполнения некоторой логики. Мне нужно проверить правильность логики в определенные дни года, но я не могу дождаться этого дня. Могу ли я изменить системную дату программно при модульном тестировании?

Ответ 1

Вам нужно использовать Mock object, а в Objective C вы можете легко делать это с помощью категорий, переопределяя только те методы, которые вам нужны. Например, вы можете использовать следующую категорию:

// ------------- File: NSDate+NSDateMock.h
@interface NSDate (NSDateMock)

 +(void)setMockDate:(NSString *)mockDate;
 +(NSDate *) mockCurrentDate;

@end

// -------------- File: NSDate+NSDateMock.m

#import "NSDate+NSDateMock.h"

@implementation NSDate (NSDateMock)

static NSDate *_mockDate;

+(NSDate *)mockCurrentDate
{
    return _mockDate;
}

+(void)setMockDate:(NSString *)mockDate
{
    _mockDate = [NSDate dateWithString:mockDate];
}

@end

и, кроме того, вам понадобится SwizzleClassMethod

void SwizzleClassMethod(Class c, SEL orig, SEL new) {

    Method origMethod = class_getClassMethod(c, orig);
    Method newMethod = class_getClassMethod(c, new);

    c = object_getClass((id)c);

    if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    else
        method_exchangeImplementations(origMethod, newMethod);
}

а затем в unit test вы сможете использовать его следующим образом

SwizzleClassMethod([NSDate class], @selector(date), @selector(mockCurrentDate));
[NSDate setMockDate:@"2007-03-24 10:45:32 +0200"];
NSLog(@"Date is: %@", [NSDate date]);