如何测试没有数据写入 NSPipe
How to test that no data is written to an NSPipe
我最近一直在研究日志框架,如果用户不希望日志消息消失,我允许用户提供 NSPipe
来关闭日志到控制台。
Logger
可以启用或禁用,禁用时不应向管道发送任何数据。
启用记录器后,很容易检查数据是否已通过管道发送,因为 availableData
立即包含数据,并触发 NSFileHandleDataAvailableNotification/readabilityHandler 块。
但是,如果您要测试数据未通过管道发送,并尝试应用 availableData
不包含任何数据的相同想法,则测试将仅在 availableData
时超时returns 一旦收到数据。
我想出了一个解决方案,那就是监听通知,如果在 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()
}
}
有什么更好的方法可以在管道接收到数据时导致测试失败,而在没有接收到数据时导致测试通过?
如评论中所述,我找到了一个单独的解决方案,它将任意数据写入管道,执行日志(这可能会或可能不会导致将更多数据写入管道),然后检索来自管道 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)
我最近一直在研究日志框架,如果用户不希望日志消息消失,我允许用户提供 NSPipe
来关闭日志到控制台。
Logger
可以启用或禁用,禁用时不应向管道发送任何数据。
启用记录器后,很容易检查数据是否已通过管道发送,因为 availableData
立即包含数据,并触发 NSFileHandleDataAvailableNotification/readabilityHandler 块。
但是,如果您要测试数据未通过管道发送,并尝试应用 availableData
不包含任何数据的相同想法,则测试将仅在 availableData
时超时returns 一旦收到数据。
我想出了一个解决方案,那就是监听通知,如果在 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()
}
}
有什么更好的方法可以在管道接收到数据时导致测试失败,而在没有接收到数据时导致测试通过?
如评论中所述,我找到了一个单独的解决方案,它将任意数据写入管道,执行日志(这可能会或可能不会导致将更多数据写入管道),然后检索来自管道 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)