测试NSLog输出

Dar*_*ust 7 xcode xctest

我正在编写一个框架,其中还包括一个可以在运行时启用/禁用的简单记录器.由于我希望对尽可能多的框架进行单元测试,我还想测试记录器是否正常工作.

记录器只需记录通过NSLog.现在我需要测试输出是否真的符合期望(即它是否真的记录并且是正确格式的输出).我找不到使用Xcode的XCTest框架做到这一点的方法.

我可以修改记录器,以便它NSLog在测试时不会使用,但这让我觉得容易出错.那么,有没有更好的方法来检查NSLog输出?

Dar*_*ust 0

我通过编写一个实用程序类来解决这个问题,该实用程序类将文件描述符重定向到文件并能够重置此重定向:

@interface IORedirector : NSObject

- (instancetype)initWithFileDescriptor:(int)fileDescriptor targetPath:(NSURL *)fileURL flags:(int)oflags mode:(mode_t)mode;

- (void)reset;

@end

@implementation IORedirector
{
    int _fileDescriptor;
    int _savedFileDescriptor;
}

- (instancetype)initWithFileDescriptor:(int)fileDescriptor targetPath:(NSURL *)fileURL flags:(int)oflags mode:(mode_t)mode
{
    _savedFileDescriptor = dup(fileDescriptor);
    if (_savedFileDescriptor == -1) {
        NSLog(@"Could not save file descriptor %d: %s", fileDescriptor, strerror(errno));
        return nil;
    }

    int tempFD = open(fileURL.path.fileSystemRepresentation, oflags, mode);
    if (tempFD == -1) {
        NSLog(@"Could not open %@: %s", fileURL.path, strerror(errno));
        close(_savedFileDescriptor);
        return nil;
    }

    if (close(fileDescriptor) == -1) {
        NSLog(@"Closing file descriptor %d failed: %s", fileDescriptor, strerror(errno));
        close(_savedFileDescriptor);
        close(tempFD);
        return nil;
    }

    if (dup2(tempFD, fileDescriptor) == -1) {
        NSLog(@"Could not replace file descriptor %d with new one for %@: %s", fileDescriptor, fileURL.path, strerror(errno));
        close(_savedFileDescriptor);
        close(tempFD);
        return nil;
    }

    _fileDescriptor = fileDescriptor;
    close(tempFD);

    return self;
}

- (void)dealloc
{
    [self reset];
}

- (void)reset
{
    if (_savedFileDescriptor == -1) return;

    if (close(_fileDescriptor) == -1) {
        NSLog(@"Closing file descriptor %d failed: %s", _fileDescriptor, strerror(errno));
        return;
    }

    if (dup2(_savedFileDescriptor, _fileDescriptor) == -1) {
        NSLog(@"Could not restore file descriptor %d: %s", _fileDescriptor, strerror(errno));
        return;
    }

    close(_savedFileDescriptor);
    _savedFileDescriptor = -1;
}

@end
Run Code Online (Sandbox Code Playgroud)

初始化程序要么返回一个有效的实例(已建立重定向),要么返回nil。立即致电reset恢复重定向。

初始化程序 和 都reset可能失败并“丢失”原始文件描述符,但窗口很小且不太可能。这可能仅在多线程应用程序中使用此类时相关(我不这样做),因此如果您打算在多线程环境中使用它,您需要确保一次只有一个初始化程序或reset可以使用全局变量运行互斥锁什么的。

使用这个类(当然,我有一个单独的测试用例),我可以重定向STDERR_FILENO到一个文件,从而捕获NSLog. 这样我就可以测试未修改的日志记录类。

创建临时文件的合适路径留给读者作为练习。