Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Testing with Snapshots
Search
Philip Brechler
June 17, 2015
Technology
61
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Testing with Snapshots
A talk I gave at CocoaHeads Berlin about testing iOS view components with FBSnapshotTestCase
Philip Brechler
June 17, 2015
Other Decks in Technology
See All in Technology
ストレスなくAIと付き合いたい!こんなときどうしてる?
namiki64
3
550
専門領域のAIをどう評価するか
bengo4com
2
200
Gemini Intelligence 入門 ― AppFunctions と Gemini Nano
takuroabe
0
270
OptunaHub: ブラックボックス最適化のためのプラットフォーム
pfn
PRO
0
140
QA4AI 2026-Oct 生成AI時代の品質保証
tokuty
1
860
AI導入は済んだ。次は統制を作り替える番だ_AI×開発組織 Summit 2026
techtekt
PRO
0
280
『SAR衛星データ解析入門』のご紹介とその応用
syuchimu
0
120
Local CI × GitHub Actions
gogutan
2
210
Temporal 最高!でも改めて「日付」について調べたら人類の負債すぎる件
riyaamemiya
0
150
会社説明資料
persolserverworks
0
9.8k
ソフトウェア ファクトリー - 再現性のあるソフトウェアの工場づくり / Software factory
iktakahiro
6
5k
二歩目のフロントエンド・ウェブアクセシビリティ
camiha
2
630
Featured
See All Featured
Building AI with AI
inesmontani
PRO
1
1.3k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
520
The Cult of Friendly URLs
andyhume
79
7k
Navigating Team Friction
lara
192
16k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Are puppies a ranking factor?
jonoalderson
2
4.1k
WCS-LA-2024
lcolladotor
0
890
Deep Space Network (abreviated)
tonyrice
0
370
Mind Mapping
helmedeiros
1
400
Accessibility Awareness
sabderemane
1
250
Transcript
Testing with Snapshots Philip Brechler • CocoaHeads Berlin
About me • iOS developer since 2008 • Mobile Lead
MOTOR-TALK.de • Developing apps for Europe’s biggest automotive community
Testing Mobile Apps • Apps are getting more complex •
Testing is essential for great quality • Testing logic with unit tests • Testing UI with UI Testing Frameworks (KIF etc.)
Problems when Testing • Logic tests are fast and easy
to write but test only a bare minimal • UI tests are slow and complex to write • Tests should encourage a good architecture
None
None
None
None
None
None
None
None
None
Testing a Cell • Testing if a cell’s layout is
correct is really hard • Testing landscape and portrait • Testing edge cases • Testing states • Testing on a lot of devices
None
Meet FBSnapshotTestCase
FBSnapshotTestCase • OpenSource Project by Jonathan Dan (Facebook) • Take
reference pictures from view components • Compare those pictures to current state
None
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
- (void)testWithViewModel { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
ThreadTableViewController *tableViewController = [storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([ThreadTableVie wController class])]; PostTableViewCell *cell = [tableViewController.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([PostTableViewCell class])]; Post *testPost = [[Post alloc]init]; [testPost setTimestamp:[NSDate dateWithTimeIntervalSince1970:1420120800]]; [testPost setAuthor:[[User alloc] init]]; testPost.author.displayName = @"Test User"; testPost.text = @"Jujubes pie wafer (…)“; CGFloat heightForCell = [PostTableViewCell heightForPostText:testPost.text cellWidth:320]; [cell setFrame:CGRectMake(0, 0, 320, heightForCell)]; PostViewModel *viewModel = [[PostViewModel alloc]initWithPost:testPost]; cell.authorNameLabel.text = viewModel.authorName; cell.authorAvatarImageView.image = [UIImage imageNamed:@"no_avatar"] ; cell.postTextView.attributedText = viewModel.text; cell.postDateLabel.text = viewModel.dateString; FBSnapshotVerifyView(cell, nil); }
None
None
None
None
None
Test Driven? • Don’t use your design mockups as references!
• Finding resizing issues is easy • Testing edge cases is easy • Helps a lot during development
Wins • Fast tests for UI components (100ms per test)
• Test multiple sizes and landscape without juggling devices • Encourages to clearly separate views and logic (MVVM) • Good at finding regression problems in complex apps
Problems • Reference images need to be taken for each
simulator once • False positives are possible (but not common) • Can not replace UI tests completely but makes the number of tests smaller
Thanks! Questions?