Domanda

I want to create unit test that check one particular case. Result of this case is logging with system function NSLog.

<2014-02-19 03:05:11> Warning bla-bla-bla. Please, check you code.

I've searched a lot, but have not found a decent solution. Is there any chance that logging operation can be captured through observation or mb Xcode console content can be retrieved in some way?

Any advice will be helpful!

EDIT Alright, I see there's some misunderstanding what I want to test. The library want to warn developer, who uses it, about some bad input. It will continue to process them anyway and will return result(mb incorrect result). But at some point of processing I check value(not initial value though) and log warning message and, then, continue to process. Even if I encapsulate this logic I don't want to have this functionality public.

È stato utile?

Soluzione

I have the same case , so what you can do is 1.Direct your log to a txt file.

+ (void)recordLog{
    NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [allPaths objectAtIndex:0];
    pathForLog = [documentsDirectory stringByAppendingPathComponent:@"FWTestLog.txt"];
    NSLog(@"path = %@",pathForLog);

    stderrSave = dup(STDERR_FILENO);
    freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
}

2.Search a the string "bla-bla-bla" pattern in the txt file.And use XCTTest to test if the string is found.

3.Close the file and delete it so the other nslog will go back to console.

+ (void)closeLog{
    fflush(stderr);
    dup2(stderrSave,STDERR_FILENO);
    close(stderrSave);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error = nil;
    [fileManager removeItemAtPath:pathForLog error:&error];
}

I wrap it inside my custom test class so that I can use it with other standard XCTTest

Altri suggerimenti

You don't show any code, but it sounds like you want to test the value of a string that, during runtime, is only appearing in the log. You can easily isolate this method to allow unit-testing to work.

So imagine the current code is:

- (void)someMethod {
    NSString *string = @"Generated using some process";
    NSLog(@"String is %@", string);
    [self useString:string];
}

This can be changed to:

- (NSString *)generateString {
    NSString *string = @"Generated using some process";
    return string;
}

- (void)someMethod {
    NSString *string = [self generateString];
    NSLog(@"String is %@", string);
    [self useString:string];
}

Your unit-test will then focus on generateString rather than someMethod.

Here is a conversion to Swift, I also added the search function:

class YourTestClass: XCTestCase {

    // Used class properties here, because only a specific output is put to the logfile, rest of the logs shall stay in the console e.g. for your build server logs.
    var stderrSave: Int32 = 0
    var logFilePath: String {
        get {
            let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
            return documentsPath! + "/FWTestLog.txt"
        }
    }

    // Will be called before you want to have all logs being redirected to your logile
    func startLogging() {
        self.stderrSave = dup(STDERR_FILENO)
        freopen(self.logFilePath.cString(using: .ascii), "a+", stderr)
    }

    // Will be called when you want to stop redirecting all logs to a separate file
    func closeLogging() {
        fflush(stderr);
        dup2(stderrSave,STDERR_FILENO);
        close(stderrSave);
        try? FileManager.default.removeItem(atPath: self.logFilePath)
    }

    // Search for the according string
    func recordLog(logged string:String) -> Bool {
        let content = try? String(contentsOfFile: self.logFilePath)
        return (content?.hasSuffix(string + "\n"))!
    }

    func testExample() {
        self.startLogging()
        var isRecorded = self.recordLog(logged: "your logged string")
        XCTAssertFalse(isRecorded, "🔴🔴 String should not have been logged yet: \"your logged string\"")
        NSLog("your logged string")
        isRecorded = self.recordLog(logged: "your logged string")
        self.closeLogging()
        XCTAssertTrue(isRecorded, "🔴🔴 Expected the String to be logged: \"your logged string\"")
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top