在 Swift 中測(cè)試 UIAlertController的方法
最近我讀了一篇在 Objective-C 中使用 control swizzling 測(cè)試 UIAlertController 的 文章 。這樣的文章總是促使我尋找一種不使用 control swizzling 也可以測(cè)試同樣?xùn)|西的方法。雖然,我知道 swizzling 是開發(fā)者的一個(gè)非常有力的工具,但我個(gè)人是盡可能去避免去使用它的。事實(shí)上,在最近的六年時(shí)間里,我只在一個(gè)應(yīng)用上用了 swizzling。所以我相信我們現(xiàn)在可以不使用 swizzling 來實(shí)現(xiàn)測(cè)試。
那么問題來了,如何在 Swift 中不使用 swizzling 來對(duì) UIAlertController 進(jìn)行測(cè)試?
我們先從我們要測(cè)試的代碼開始吧。我已經(jīng)添加一個(gè)按鈕到 Storyboard 中。(我之所以使用 Storyboard 為了讓那些不想用代碼寫界面的小伙伴有個(gè)更直觀的感受)當(dāng)按下這個(gè)按鈕就會(huì)出現(xiàn)一個(gè)彈窗(alert),它有標(biāo)題、消息內(nèi)容,還有兩個(gè)按鈕,分別是 OK 和取消(Cancel)。
下面是這段代碼:
import UIKit class ViewController: UIViewController { var actionString: String? @IBAction func showAlert(sender: UIButton) { let alertViewController = UIAlertController(title: "Test Title", message: "Message", preferredStyle: .Alert) let okAction = UIAlertAction(title: "OK", style: .Default) { (action) -> Void in self.actionString = "OK" } let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in self.actionString = "Cancel" } alertViewController.addAction(cancelAction) alertViewController.addAction(okAction) presentViewController(alertViewController, animated: true, completion: nil) } }
注意,在這個(gè)例子中彈窗動(dòng)作沒有做什么具體的操作,他們只表示能驗(yàn)證單元測(cè)試。
讓我們開始一個(gè)簡(jiǎn)單的測(cè)試:測(cè)試這個(gè)彈窗控制器的標(biāo)題和消息內(nèi)容。
測(cè)試的代碼如下:
import XCTest @testable import TestingAlertExperiment class TestingAlertExperimentTests: XCTestCase { var sut: ViewController! override func setUp() { super.setUp() sut = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as! ViewController UIApplication.sharedApplication().keyWindow?.rootViewController = sut } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } } ```
我們需要設(shè)置 sut 為根視圖控制器,否則視圖控制器不能彈出這個(gè)彈窗視圖控制器。
添加 UIAlertController 測(cè)試標(biāo)題的代碼如下:
```Swift func testAlert_HasTitle() { sut.showAlert(UIButton()) XCTAssertTrue(sut.presentedViewController is UIAlertController) XCTAssertEqual(sut.presentedViewController?.title, "Test Title") } ```
這很簡(jiǎn)單?,F(xiàn)在讓我們測(cè)試 UIAlertController 的取消按鈕。這里有一個(gè)問題:無法獲取彈窗動(dòng)作的閉包。因此我們需要模擬彈窗動(dòng)作,為了存儲(chǔ)這個(gè) handler 并在測(cè)試中調(diào)用它,看彈窗動(dòng)作是否和我們預(yù)期的一樣。在測(cè)試用例中添加這樣一個(gè)類:
```Swift class MockAlertAction : UIAlertAction { typealias Handler = ((UIAlertAction) -> Void) var handler: Handler? var mockTitle: String? var mockStyle: UIAlertActionStyle convenience init(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)?) { self.init() mockTitle = title mockStyle = style self.handler = handler } override init() { mockStyle = .Default super.init() } }
這個(gè)模擬類的主要工作是捕獲 handler 塊,以備后用。現(xiàn)在我們需要將這個(gè)模擬的類插入到實(shí)現(xiàn)代碼中。將視圖控制器中的代碼換成下面這個(gè):
import UIKit class ViewController: UIViewController { var Action = UIAlertAction.self var actionString: String? @IBAction func showAlert(sender: UIButton) { let alertViewController = UIAlertController(title: "Test Title", message: "Message", preferredStyle: .Alert) let okAction = Action.init(title: "OK", style: .Default) { (action) -> Void in self.actionString = "OK" } let cancelAction = Action.init(title: "Cancel", style: .Cancel) { (action) -> Void in self.actionString = "Cancel" } alertViewController.addAction(cancelAction) alertViewController.addAction(okAction) presentViewController(alertViewController, animated: true, completion: nil) } } ```
我們添加了一個(gè)類變量`Action`,并設(shè)置為`UIAlertAction.self`。這個(gè)變量我們會(huì)在初始化彈窗動(dòng)作時(shí)使用。這就能讓我們?cè)跍y(cè)試時(shí)可以重寫它。像這樣:
```Swift func testAlert_FirstActionStoresCancel() { sut.Action = MockAlertAction.self sut.showAlert(UIButton()) let alertController = sut.presentedViewController as! UIAlertController let action = alertController.actions.first as! MockAlertAction action.handler!(action) XCTAssertEqual(sut.actionString, "Cancel") }
首先我們插入了這個(gè)彈窗動(dòng)作。之后我們調(diào)用代碼彈出彈窗視圖控制器。我們從呈現(xiàn)的視圖控制器中獲取了取消動(dòng)作,并且成功調(diào)用了捕獲的 handler 塊。最后一步就是去斷言當(dāng)前的動(dòng)作是否和我們預(yù)期的一樣。
就是這樣,一種很簡(jiǎn)單的又不使用 swizzling 來測(cè)試 UIAlertViewController 的方式。
以上內(nèi)容是關(guān)于在 Swift 中測(cè)試 UIAlertController的方法,希望對(duì)大家有用。
相關(guān)文章
Swift網(wǎng)絡(luò)請(qǐng)求庫(kù)Alamofire使用詳解
這篇文章主要為大家詳細(xì)介紹了Swift網(wǎng)絡(luò)請(qǐng)求庫(kù)Alamofire的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08如何使用Swift來實(shí)現(xiàn)一個(gè)命令行工具的方法
這篇文章主要介紹了如何使用Swift來實(shí)現(xiàn)一個(gè)命令行工具,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05通過Notification.Name看Swift是如何優(yōu)雅的解決String硬編碼
這篇文章主要給大家介紹了通過Notification.Name看Swift是如何優(yōu)雅的解決String硬編碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08iOS Swift UICollectionView橫向分頁(yè)滾動(dòng),cell左右排版問題詳解
UICollectionView是iOS中比較常見的一個(gè)控件,這篇文章主要給大家介紹了關(guān)于iOS Swift UICollectionView橫向分頁(yè)滾動(dòng),cell左右排版問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能
這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能,在“登錄”和“注冊(cè)”頁(yè)面也有相似功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03