在什么情况下,人们会在快速测试中使用expectationForNotification

时间:2015-04-22 15:28:31

标签: swift testing

我对 expectationForNotification 的内容/时间有点困惑,而不是 expectationWithDescription 。我已经无法在swift中找到任何明确的例子来说明你何时以及如何处理这个电话。

我假设它可能会测试通知,但看起来它可能只是围绕整个addObserver()通知中心呼叫的更方便的包装器。

有人可以简要解释一下它的用途,何时使用它,以及几行示例代码?

由于

3 个答案:

答案 0 :(得分:24)

正如您已经想象的那样 expectationForNotification 是检查通知是否被引发的便利期望。

这个测试:

func testItShouldRaiseAPassNotificationV1() {
    let expectation = expectationWithDescription("Notification Raised")
    let sub = NSNotificationCenter.defaultCenter().addObserverForName("evPassed", object: nil, queue: nil) { (not) -> Void in
        expectation.fulfill()
    }
    NSNotificationCenter.defaultCenter().postNotificationName("evPassed", object: nil)
    waitForExpectationsWithTimeout(0.1, handler: nil)
    NSNotificationCenter.defaultCenter().removeObserver(sub)
}

可以替换为:

func testItShouldRaiseAPassNotificationV2() {
    expectationForNotification("evPassed", object: nil, handler: nil)
    NSNotificationCenter.defaultCenter().postNotificationName("evPassed", object: nil)
    waitForExpectationsWithTimeout(0.1, handler: nil)
}

您可以在Objc.io number中找到一个很好的解释。

答案 1 :(得分:1)

为了理解expectation(forNotification:, object:, handler:)expectation(description:)之间的区别,我使用Swift 3构建了一个简单的XCTestCase子类。

在这里,我们要测试发布BlockOperation的{​​{1}}是否更新了我们班级的指定Notification属性,请求值为50。

1。将Int?expectation(description:)

一起使用
addObserver(_:, selector:, name:, object:)

2。将import XCTest class AppTests: XCTestCase { var testExpectation: XCTestExpectation? var finalAmount: Int? func testFinalAmount() { let notificationName = Notification.Name(rawValue: "BlockNotification") // Set self as an observer let selector = #selector(updateFrom(notification:)) NotificationCenter.default.addObserver(self, selector: selector, name: notificationName, object: nil) // Set expectation testExpectation = expectation(description: "Did finish operation expectation") // Set and launch operation block and wait for expectations let operation = BlockOperation(block: { NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["amount": 50]) }) operation.start() waitForExpectations(timeout: 3, handler: nil) // Asserts XCTAssertNotNil(finalAmount) XCTAssertEqual(finalAmount, 50) } func updateFrom(notification: Notification) { if let amount = notification.userInfo?["amount"] as? Int { self.finalAmount = amount } self.testExpectation?.fulfill() } } expectation(description:)

一起使用
addObserver(forName:, object:, queue:, using:)

3。使用import XCTest class AppTests: XCTestCase { var finalAmount: Int? func testFinalAmount() { let notificationName = Notification.Name(rawValue: "BlockNotification") // Set expectation let testExpectation = expectation(description: "Did finish operation expectation") // Set self as an observer let handler = { (notification: Notification) -> Void in if let amount = notification.userInfo?["amount"] as? Int { self.finalAmount = amount } testExpectation.fulfill() } NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: nil, using: handler) // Set and launch operation block and wait for expectations let operation = BlockOperation(block: { NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["amount": 50]) }) operation.start() waitForExpectations(timeout: 3, handler: nil) // Asserts XCTAssertNotNil(finalAmount) XCTAssertEqual(finalAmount, 50) } }

expectation(forNotification:, object:, handler:)

TL;博士

在我们的测试用例中使用import XCTest class AppTests: XCTestCase { var finalAmount: Int? func testFinalAmount() { let notificationName = Notification.Name(rawValue: "BlockNotification") // Set expectation let handler = { (notification: Notification) -> Bool in if let amount = notification.userInfo?["amount"] as? Int { self.finalAmount = amount } return true } expectation(forNotification: notificationName.rawValue, object: nil, handler: handler) // Set and launch operation block and wait for expectations let operation = BlockOperation(block: { NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["amount": 50]) }) operation.start() waitForExpectations(timeout: 3, handler: nil) // Asserts XCTAssertNotNil(finalAmount) XCTAssertEqual(finalAmount, 50) } } 代替expectation(forNotification: String, object:, handler:)提供了一些优势:

  • 我们的测试现在需要更少的代码行(31而不是35或37行),
  • 我们的测试不再需要将expectation(description:)addObserver(_:, selector:, name:, object:)#selector一起使用,
  • 我们的测试不再需要将addObserver(forName:, object:, queue:, using:)实例声明为我们类的属性或我们的测试方法的范围变量,并将其标记为在XCTestExpectation的某个时刻已经满足

答案 2 :(得分:1)

您不应该依赖UIKit的NotificationCenter。只有当您的类型将命令发送到正确的对象时,才创建类型的边界并进行测试。以下是如何使NotificationCenter采用您的代码的示例。 (我现在无法访问Xcode,所以可能会有一些错字)

protocol NotificationCenterProtocol {
  func post(notification: Notification)
}

extension NotificationCenter: NotificationCenterProtocol {}

class SpyNotificationCenter: NotificationCenterProtocol {
  var didPostNotification = false

  func post(notification: Notification) {
    didPostNotification = true
  }

}