私はSwiftで作業しています。ページを更新したいので、通知を使用して送信します。あるViewControllerに通知を投稿し、別のViewControllerにオブザーバーを追加すると、完全に機能します。私がやりたいのは、Swiftでユニットテストを追加することです。多くのサイトをチェックしましたが、できませんでした。 Swiftは初めてで、どこから始めればよいかわかりません。
基本的には、ボタンをクリックすると通知が投稿され、次のView Controllerがロードされると、通知オブザーバーが追加されます。
ユニットテストを行うにはどうすればよいですか
前もって感謝します
編集:コード
NSNotificationCenter.defaultCenter().postNotificationName("notificationName", object: nil)
オブザーバーを
NSNotificationCenter.defaultCenter().addObserver(self, selector: "vvv:",name:"notificationName", object: nil)
XCTest
には、通知をテストするための特別なクラスがあります: XCTNSNotificationExpectation
。これらの期待の1つを作成し、通知を受信するとそれが満たされます。あなたはそれを次のように使うでしょう:
_// MyClass.Swift
extension Notification.Name {
static var MyNotification = Notification.Name("com.MyCompany.MyApp.MyNotification")
}
class MyClass {
func sendNotification() {
NotificationCenter.default.post(name: .MyNotification,
object: self,
userInfo: nil)
}
}
// MyClassTests.Swift
class MyClassTests: XCTestCase {
let classUnderTest = MyClass()
func testNotification() {
let notificationExpectation = expectation(forNotification: .MyNotification,
object: classUnderTest,
handler: nil)
classUnderTest.sendNotification()
waitForExpectations(timeout: 5, handler: nil)
}
}
_
XCTestCase
's expectation(forNotification:object:handler:)
は、 XCTNSNotificationExpectation
のインスタンスを作成するための便利なメソッドです。 =ですが、より詳細に制御するために、インスタンス化して自分で構成することができます。 ドキュメント を参照してください。
一般的な解決策は次のとおりです。依存性注入(DI)を使用して、コンポーネントをユニットテスト可能にします。 DIフレームワークを使用する(Swiftはまだ存在する)ための適切なフレームワークがあるかどうかはわかりません)か、ネイティブアプローチを使用する(つまり、オブジェクトを渡す)かを選択できます。
問題に対する考えられるアプローチの1つは、NSNotificationCenter
をラップして、モック可能/注入可能にすることです。
これは、依存関係を切り離す方法の基本的な考え方にすぎません。以下のコードをコピーして貼り付けるだけでなく、理解しなくても機能することを期待してください。
import Foundation
protocol NotificationCenter {
func postNotificationName(name: String, object: AnyObject?)
// you can make it take the arguments as NSNotificationCenter.addObserver
func addObserver(callback: AnyObject? -> Void)
}
class MyNotificationCenter : NotificationCenter {
var _notificationCenter: NSNotificationCenter
init(_ center: NSNotificationCenter) {
_notificationCenter = center
}
func postNotificationName(name: String, object: AnyObject?) {
// call NSNotificationCenter.postNotificationName
}
func addObserver(callback: AnyObject? -> Void) {
// call NSNotificationCenter.addObserver
}
}
class MockNotificationCenter : NotificationCenter {
var postedNotifications: [(String, AnyObject?)] = []
var observers: [AnyObject? -> Void] = []
func postNotificationName(name: String, object: AnyObject?) {
postedNotifications.append((name, object))
}
func addObserver(callback: AnyObject? -> Void) {
observers.append(callback)
}
}
class MyView {
var notificationCenter: NotificationCenter
init(notificationCenter: NotificationCenter) {
self.notificationCenter = notificationCenter
}
func handleAction() {
self.notificationCenter.postNotificationName("name", object: nil)
}
}
class MyController {
var notificationCenter: NotificationCenter
init(notificationCenter: NotificationCenter) {
self.notificationCenter = notificationCenter
}
func viewDidLoad() {
self.notificationCenter.addObserver {
println($0)
}
}
}
// production code
// in AppDeletate.applicationDidFinishLaunching
let notificationCenter = MyNotificationCenter(NSNotificationCenter.defaultCenter())
// pass it to your root view controller
let rootViewController = RootViewController(notificationCenter: notificationCenter)
// or
rootViewController.notificationCenter = notificationCenter
// in controller viewDidLoad
self.myView.notificationCenter = self.notificationCenter
// when you need to create controller
// pass notificationCenter to it
let controller = MyController(notificationCenter: notificationCenter)
// in unit test
func testMyView() {
let notificationCenter = MockNotificationCenter()
let myView = MyView(notificationCenter: notificationCenter)
// do something with myView, assert correct notification is posted
// by checking notificationCenter.postedNotifications
}
func testMyController() {
let notificationCenter = MockNotificationCenter()
let myController = MyController(notificationCenter: notificationCenter)
// assert notificationCenter.observers is not empty
// call it and assert correct action is performed
}