Как проверить, что данные не записываются в NSPipe

В последнее время я работаю над структурой ведения журналов, и я разрешаю пользователю предоставлять NSPipe для журналов, чтобы они закрывались, если они не хотят, чтобы сообщения журнала отправлялись на консоль.

Logger может быть включен или отключен, и когда он отключен, он не должен отправлять данные по каналу.

Легко проверить, были ли данные отправлены по каналу, когда регистратор включен, так как availableData немедленно содержит данные, и запускается блок NSFileHandleDataAvailableNotification/readabilityHandler.

Однако, если вы должны проверить, что данные не были отправлены по конвейеру, и попытаетесь применить ту же идею, что availableData не будет содержать никаких данных, тесты прекратятся по тайм-ауту, так как availableData вернется только после получения данных.

Я придумал одно решение, которое заключалось бы в том, чтобы прослушать уведомление, и если оно не было получено через X секунд, выполнить ожидание того, что уведомление не было получено, с предпосылкой, что ожидание будет выполнено дважды (что приводит к сбою теста), если получено уведомление.

Проблема с этим подходом в том, что если по какой-то причине пайп все-таки получает какие-то данные, то после того, как ожидание сбылось в блоке readabilityHandler, тест сразу завершается успешно, и ожидание не сбывается во второй раз:

func testDisabledLoggerDoesntLog() {
    let logger = Logger()
    let pipe = NSPipe()

    logger.pipe = pipe
    logger.enabled = false

    let expectation = expectationWithDescription("handler not triggered")
    logger.pipe!.fileHandleForReading.readabilityHandler = { handler in
        expectation.fulfill()
    }

    logger.debug("Test message")

    fulfillAfter(expectation, time: 2)

    waitForExpectationsWithTimeout(3, handler: nil)
}

func fulfillAfter(expectation: XCTestExpectation, time: Double = 4) {
    let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(time * Double(NSEC_PER_SEC)))
    dispatch_after(delayTime, dispatch_get_main_queue()) {
        expectation.fulfill()
    }
}

Каким может быть лучший подход, который приведет к провалу теста, если канал получает данные, и к прохождению теста, если нет?


person max_    schedule 03.07.2016    source источник
comment
Как насчет вызова readDataOfLength(1) в обработчике файлов? Можно ли ожидать, что это вызовет исключение?   -  person Aaron Brager    schedule 03.07.2016
comment
@AaronBrager К сожалению, readDataOfLength не проходит. Как и availableData, он является синхронным и ожидает получения данных как минимум указанной длины, прежде чем вернуться.   -  person max_    schedule 03.07.2016
comment
@AaronBrager Я мог бы попробовать записать данные определенной длины в канал в тесте, зарегистрировать некоторые данные и проверить, равна ли длина доступных данных длине данных, которые я написал сам?   -  person max_    schedule 03.07.2016
comment
^ Кажется, это работает отлично, и теперь тесты проходят и не проходят, как и ожидалось. Я разместил его как ответ, и мне будет интересно узнать, существуют ли какие-либо лучшие решения.   -  person max_    schedule 03.07.2016


Ответы (1)


Как указано в комментариях, я нашел отдельное решение, которое записывает произвольные данные в канал, выполняет журнал (что может привести или не привести к записи дополнительных данных в канал), а затем извлекает данные из availableData канала. .

Если длина availableData равна длине произвольных данных, то ясно, что лог не записывался в канал. В противном случае, если длина больше, чем данные, записанные тестом, журнал действительно был выполнен и записал свои данные в канал.

let logger = Logger()
let pipe = NSPipe()

logger.pipe = pipe
logger.enabled = false
logger.useCurrentThread = true // The logs generally use a background thread to prevent interrupting the main queue. In this test, the current thread must be used in order for it to be synchronous.

let writtenData = "written data".dataUsingEncoding(NSUTF8StringEncoding)!
logger.pipe!.fileHandleForWriting.writeData(writtenData)

logger.debug("Test message")

XCTAssertEqual(logger.pipe!.fileHandleForReading.availableData.length, writtenData.length)
person max_    schedule 03.07.2016