在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 截圖測(cè)試
與四軸無(wú)人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測(cè)試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開(kāi)發(fā)
Collection View 動(dòng)畫
截圖測(cè)試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫解釋
響應(yīng)式 Android 應(yīng)用
初識(shí) TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測(cè)試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫
常見(jiàn)的后臺(tái)實(shí)踐
糟糕的測(cè)試
避免濫用單例
數(shù)據(jù)模型和模型對(duì)象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場(chǎng)
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測(cè)試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無(wú)人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測(cè)試
值對(duì)象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測(cè)試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場(chǎng)
游戲
調(diào)試核對(duì)清單
View Controller 容器
學(xué)無(wú)止境
XCTest 測(cè)試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲(chǔ)
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺(jué)
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫(kù)支持
Fetch 請(qǐng)求
導(dǎo)入大數(shù)據(jù)集
iOS 開(kāi)發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語(yǔ)言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識(shí)別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過(guò)程

截圖測(cè)試

開(kāi)發(fā)者對(duì)于為自己的應(yīng)用寫測(cè)試有自己的動(dòng)機(jī)。雖然我認(rèn)為應(yīng)該寫測(cè)試,但是這篇文章不是來(lái)勸說(shuō)你來(lái)做這個(gè)的。

為一個(gè) app 的表現(xiàn)層寫測(cè)試是一件棘手的工作。Apple 對(duì)于對(duì)象的邏輯測(cè)試已經(jīng)有內(nèi)建的支持,但是卻沒(méi)有支持測(cè)試那些界面代碼的結(jié)果。這個(gè)功能上的鴻溝實(shí)際上造成了很多開(kāi)發(fā)者因?yàn)榻缑鏈y(cè)試的復(fù)雜性而選擇忽視它。

當(dāng) Facebook 發(fā)布 FBSnapshotTestCaseCocoaPods 的時(shí)候,我起初還因?yàn)檫@個(gè)理由忽視了它, 還好我的同事沒(méi)有。

基于界面的測(cè)試意味著驗(yàn)證你用戶最終看到的是不是你希望用戶看到的。測(cè)試界面可以保證不同版本,不同狀態(tài)的視圖看起來(lái)可以保持一致。界面測(cè)試可以用來(lái)提供一個(gè)高級(jí)別的測(cè)試,這涵蓋了很多相關(guān)對(duì)象的用例。

它如何運(yùn)行

FBSnapShotTestCase 將一個(gè) UIView 或者 CALayer 的子類渲染為一個(gè) UIImage。這個(gè)截圖被用和一個(gè)已經(jīng)保存了的截圖進(jìn)行比對(duì),從而創(chuàng)建測(cè)試并生成測(cè)試的版本。當(dāng)測(cè)試失敗的時(shí)候,將創(chuàng)建一個(gè)失敗的測(cè)試的參考圖片,并且創(chuàng)建一個(gè)另外的圖像來(lái)表現(xiàn)兩者的不同之處。

這是一個(gè)失敗的測(cè)試的例子,原因是我們的一個(gè) View Controller 中 gird 元素比預(yù)期的要少:

http://wiki.jikexueyuan.com/project/objc/images/15-6.png" alt="" />

它通過(guò)將 view 或者 layer 以及已經(jīng)存在的截圖渲染到兩個(gè) CGContextRefs,并且用 C 函數(shù) memcmp() 來(lái)進(jìn)行內(nèi)存比較。這樣的比較會(huì)非???,我在一臺(tái) MacBook Air 上生成 iPad 或者 iPhone 的全屏截圖并進(jìn)行測(cè)試,每張圖耗時(shí)在 0.013 到 0.086 秒之間。

當(dāng)配置好以后,它默認(rèn)會(huì)將參考圖片存儲(chǔ)到你項(xiàng)目的 [Project]Tests 目錄里面的一個(gè)叫 ReferenceImages 的子文件夾里。文件夾中是根據(jù)你的測(cè)試用例的類名建立的文件夾,在測(cè)試?yán)募A中是每個(gè)測(cè)試的參考圖片。當(dāng)一個(gè)測(cè)試失敗的時(shí)候,它會(huì)將失敗的結(jié)果存儲(chǔ)下來(lái),另外再存儲(chǔ)一張這個(gè)結(jié)果和參考圖片的差異對(duì)比所生成圖片。三張圖片都會(huì)放到應(yīng)用的 tmp 目錄下,截圖測(cè)試同時(shí)會(huì)用 NSLog 在控制臺(tái)輸出一條命令,你可以用這條命令來(lái)啟動(dòng) Kaleidoscope 并進(jìn)行可視化的比較。

安裝

我們就不在這里兜圈子了:你應(yīng)該在使用 CocoaPods 吧,所以安裝僅僅需要在你的 Podfile 的測(cè)試 target 里面加入 pod "FBSnapshotTestCase"。運(yùn)行 pod install 就可以安裝這個(gè)庫(kù)了。

帶截圖的 XCTest

默認(rèn)的截圖測(cè)試需要繼承 FBSnapshotTestCase 而不是 XCTestCase,然后使用 FBSnapshotVerifyView(viewOrLayer, "optional identifier") 宏來(lái)和已經(jīng)存在的圖片驗(yàn)證比較。這里的子類有一個(gè) recordMode 的 boolean 屬性。當(dāng)設(shè)置了這個(gè)值的時(shí)候,會(huì)錄制一個(gè)新的截圖而不是把結(jié)果和參考圖片做比較。

@interface ORSnapshotTestCase : FBSnapshotTestCase
@end

@implementation ORSnapshotTestCase

- (void)testHasARedSquare
{
    // Removing this will verify instead of recording
    self.recordMode = YES;

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];
    view.backgroundColor = [UIColor redColor];
    FBSnapshotVerifyView(view, nil);
}

@end

缺點(diǎn)

沒(méi)有事情是完美的。讓我們談?wù)劜缓玫囊幻姘伞?/p>

  • 測(cè)試異步的代碼很困難。這是在 Cocoa 的測(cè)試中經(jīng)常出現(xiàn)的問(wèn)題。我有兩個(gè)解決方案。你可以使用像 Specta 或者像 Kiwi 這樣的測(cè)試框架,它提供了多次運(yùn)行斷言直到超時(shí)或者成功。這意味著你可以給它 0.5 秒的時(shí)間運(yùn)行,同時(shí)測(cè)試可能被重復(fù)多次。或者,你還可以在開(kāi)發(fā)你的應(yīng)用代碼的過(guò)程中,讓異步的代碼在做了標(biāo)記的時(shí)候同步運(yùn)行。
  • 有些組件測(cè)試起來(lái)很困難。有兩個(gè)需要注意的例子:在測(cè)試中一些 UIView 類不能在沒(méi)有 frame 的時(shí)候初始化,所以請(qǐng)總是給你的 view 一個(gè) frame 來(lái)避免 <Error>: CGContextAddRect: invalid context 0x0. [..] 這樣的錯(cuò)誤信息。 如果你使用了很多 Auto Layout 代碼,那么就不會(huì)那么簡(jiǎn)單了?;?CATiledLayer 的 view 需要在 main screen 上并且在渲染瓦片 (tiles) 前被展現(xiàn)出來(lái)。它們同樣是異步渲染的。我一般為這些測(cè)試加入 兩秒等待。
  • 蘋果的操作系統(tǒng)補(bǔ)丁會(huì)改變部件的渲染方式。比如 Apple 在 iOS 7.1 悄悄改變了字體微調(diào) (font hinting),所有使用到 UILabels 的截圖都需要重新錄制。
  • 每一個(gè)截圖是一個(gè)存在你倉(cāng)庫(kù)里面的 PNG 文件,對(duì)我的情況來(lái)說(shuō),每個(gè)文件通常大小在 30-100kb 之間。我用 "@2x" 模式記錄了所有的測(cè)試。截圖隨著被記錄的 view 的增多而增長(zhǎng)。

優(yōu)點(diǎn)

  • 我最終做到測(cè)試了。我通過(guò)對(duì)每個(gè)通過(guò)改變對(duì)象而得到的不同的 view 的狀態(tài)編寫了截圖測(cè)試。這讓我能夠讓在單次的測(cè)試中馬上看到不同狀態(tài)的變化。不用在我的 app 中進(jìn)行點(diǎn)擊來(lái)進(jìn)入對(duì)應(yīng)的視圖,然后改變狀態(tài)。我只需要看看 FBSnapshotTestCase 渲染的視圖,這省去了很多開(kāi)發(fā)時(shí)間。
  • 截圖測(cè)試在你運(yùn)行其他測(cè)試的同時(shí)運(yùn)行,不需要作為另外的測(cè)試 scheme 進(jìn)行。它用和其他測(cè)試相同的語(yǔ)言書寫。它們大多數(shù)情況下可以在不將視圖顯示在屏幕上的時(shí)候運(yùn)行。
  • 截圖可以讓代碼審查變得更具體。首先是測(cè)試,它們提供一種承諾,說(shuō)明將要出現(xiàn)的變化。之后是截圖,證明測(cè)試的承諾是正確的。最后是代碼庫(kù)中的變更。在這個(gè)時(shí)候,你已經(jīng)知道變化的內(nèi)容了,你不僅對(duì)內(nèi)在的改變清楚明白,也對(duì)用戶在外表上將看到的變化了然于胸。
  • 讓代碼審查可視化,可以讓設(shè)計(jì)師也參與其中。他們通過(guò)監(jiān)測(cè)項(xiàng)目的倉(cāng)庫(kù)里面的圖片控制變化。
  • 我發(fā)現(xiàn)寫截圖測(cè)試可以提供更多的測(cè)試覆蓋度。我不相信 100% 的單元測(cè)試覆蓋度就是最優(yōu)方案。我盡量做實(shí)用的測(cè)試,測(cè)試大多數(shù)引入的變化。截圖測(cè)試在不用指定代碼路徑的時(shí)候就測(cè)試了很多代碼路徑。這是因?yàn)榻貓D測(cè)試可以很容易地測(cè)試一系列系統(tǒng)元素結(jié)合的結(jié)果。通過(guò)比較截圖可以方便的,你可以很快速地達(dá)到可觀的測(cè)試覆蓋率。
  • 截圖測(cè)試非常快,在 Macbook Air 中使用 retina 的 iPad 尺寸的圖片平均每個(gè)測(cè)試需要運(yùn)行 0.015 到 0.080 秒。一個(gè)應(yīng)用里面運(yùn)行上百個(gè)測(cè)試都沒(méi)問(wèn)題。我在開(kāi)發(fā)的應(yīng)用 有數(shù)百個(gè)測(cè)試,但是它們能在 5 秒以內(nèi)運(yùn)行完畢。

工具

FBSnapShots + Specta + Expecta

我沒(méi)有使用原生的 XCTest。我用的是 Specta 和 Expecta,因?yàn)槭褂玫臅r(shí)候更加簡(jiǎn)單,可讀性也更強(qiáng)。這是你在創(chuàng)建一個(gè)新 CocoaPod 的時(shí)候的初始配置。我是 Expecta+Snapshots 這個(gè) pod 的貢獻(xiàn)者,它為 FBSnapshotTestCase 提供了一個(gè)類似 Expecta 的 API。它會(huì)為截圖命名,同時(shí)可以在視圖的生命周期里面選擇性運(yùn)行。我的 Podfile 看起來(lái)是這樣子的:

target 'MyApp Tests', :exclusive => true do
    pod 'Specta','~> 1.0'
    pod 'Expecta', '~> 1.0'
    pod 'Expecta+Snapshots', '~> 1.0'
end

然后,我的測(cè)試看起來(lái)會(huì)是這個(gè)樣子的:

SpecBegin(ORMusicViewController)

it (@"notations in black and white look correct", ^{
    UIView *notationView = [[ORMusicNotationView alloc] initWithFrame:CGRectMake(0, 0, 80, 320)];
    notationView.style = ORMusicNotationViewStyleBlackWhite;

    expect(notationView).to.haveValidSnapshot();
});

it (@"Initial music view controller looks corrects", ^{
    id contoller = [[ORMusicViewController alloc] initWithFrame:CGRectMake(0, 0, 80, 80)];
    controller.view.frame = [UIScreen mainScreen].bounds;

    expect(controller).to.haveValidSnapshot();
});

SpecEnd

Snapshots Xcode 插件

解析 console 里面的日志來(lái)找到圖片要花不少力氣,裝載不同的失敗測(cè)試到一個(gè)可視化的工具比如 Kaleidoscope 里,需要運(yùn)行不少命令行程序。

為了處理幾乎所有這些常見(jiàn)的場(chǎng)景,我寫了一個(gè) Xcode 插件 Snapshots。它可以通過(guò) Alcatraz 安裝或者自己編譯。它可以讓在 Xcode 中失敗測(cè)試的失敗和成功的圖片的比較變得非常容易。

總結(jié)

FBSnapshotTestCase 給你一個(gè)測(cè)試視圖相關(guān)代碼的方法,它可以用來(lái)測(cè)試視圖相關(guān)的狀態(tài)而不用依賴于模擬器。如果你使用 Xcode 的話,你可以考慮和我的插件 Snapshots 一起使用它。有些時(shí)候它可能會(huì)讓人很煩,但是這還是值得的。它可以讓設(shè)計(jì)師參與代碼審查階段,也可以成為為現(xiàn)有項(xiàng)目寫測(cè)試的簡(jiǎn)單的第一步,你可以試一試。

開(kāi)源項(xiàng)目案例: