我正在编写一个框架,其中还包含一个可在运行时启用/禁用的简单记录器。由于我希望对尽可能多的框架进行单元测试,我还想测试记录器是否正常工作。
记录器只需通过NSLog
进行记录。现在我需要测试输出是否真的符合期望(即它是否真的记录并且是正确格式的输出)。我无法使用Xcode的XCTest框架找到一种方法。
我可以修改记录器,以便它在测试时不会使用NSLog
,但这让我觉得容易出错。那么,有没有更好的方法来检查NSLog
输出?
答案 0 :(得分:1)
让记录器输出字符串。有另一个对象打印这些。这样,您可以单独测试第一个对象与第二个对象。
答案 1 :(得分: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
初始化程序返回有效实例(已建立重定向)或nil
。调用reset
立即恢复重定向。
初始值设定项和reset
都可能失败并且"丢失"原始文件描述符,但窗口很小,不太可能。这可能仅在多线程应用程序中使用此类时才有意义(我不会这样做),因此如果您打算在多线程环境中使用此类,则需要确保只有一个初始化程序或reset
可以使用全局互斥体或其他东西一次运行。
使用这个类(我当然有一个单独的测试用例),我可以将STDERR_FILENO
重定向到一个文件,从而捕获NSLog
的输出。这样我可以测试未修改的日志记录类。
创建一个合适的临时文件路径留给读者练习。