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 on iOS
Search
AppFoundry
December 10, 2015
Technology
320
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Testing on iOS
A presentation by Joris Dubois (AppFoundry) for the December 2015 Mobel user group meetup
AppFoundry
December 10, 2015
More Decks by AppFoundry
See All by AppFoundry
Introductie iOS - Jens
appfoundrybe
0
130
Android In Practice
appfoundrybe
0
160
Android Introduction 3.0 by Siebe
appfoundrybe
0
160
Android in Practice (long)
appfoundrybe
0
240
React Native - cross-platform mobile app development
appfoundrybe
0
220
React Native Storybook
appfoundrybe
0
510
the ionic crash course
appfoundrybe
1
220
View based apps with Conductor
appfoundrybe
0
670
Android Accessibility at GDG Devfest Brussels 2016
appfoundrybe
0
700
Other Decks in Technology
See All in Technology
HolmesGPTで始めるSREエージェント入門!プラットフォームの障害調査はAIにお任せ 〜
sanghyuk
0
250
AIエージェントを安全で速い現場監督にする:Jev・Obsidian・メタハーネス
x5gtrn
PRO
0
140
Mastering Agentic Development: Harness Engineering for Effective Coding Agents
konippi
3
660
AIに会社の文脈を理解させる技術~上流工程・非エンジニアにも広げるハーネスエンジニアリング実践~
ochtum
0
190
ボードゲームの遊び相手をFoundation Modelsで作る / iOSDC Japan 2026
genda
0
240
キャリアLT今日までそして明日から
kentapapa
1
130
Claude Designがめちゃくちゃ便利なので使ってほしい
diggymo
0
150
AIに書かせて、プラットフォームで縛る ― EKSプラットフォームで実践した責任境界と権限設計
elmodev09
1
1.1k
Argo CDとAtlantisで実現するインフラ管理のセルフサービス化──小規模SREチームで支えるプラットフォーム
cassius7
0
250
20260930_Gemma4_Hands-on
tsho
0
160
AI感のないAWS構成図をAIエージェントに描かせたい!
sagochiko
2
480
Lambda MicroVMsが分からなすぎたので使い所を1から考えてみた
tsukuboshi
1
250
Featured
See All Featured
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
290
KATA
mclloyd
PRO
35
16k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
510
Building Adaptive Systems
keathley
44
3.2k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
350
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Site-Speed That Sticks
csswizardry
13
1.5k
Are puppies a ranking factor?
jonoalderson
2
4k
We Are The Robots
honzajavorek
0
380
Git: the NoSQL Database
bkeepers
PRO
432
67k
Transcript
Your hosts Filip Maelbrancke Consultant @ AppFoundry fi
[email protected]
@fmaelbrancke Joris
Dubois Consultant @ AppFoundry
[email protected]
@DuboisJoris
AppFoundry appfoundry.be
None
Patterns
Dependency Injection a 25-dollar term for a 5-cent concept
Coding Example DI: Spot the problem #import <Foundation/Foundation.h> @interface UserDefaultManager
: NSObject - (void)registerLeetInteger; @end #import "UserDefaultManager.h" @implementation UserDefaultManager - (void)registerLeetInteger { [[[NSUserDefaults alloc] initWithSuiteName:@"LeetAppGroup"] setInteger:1337 forKey:@"leet"]; } @end
Coding Example DI: Constructor Injection #import <Foundation/Foundation.h> @interface UserDefaultManager :
NSObject - (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults; - (void)registerLeetInteger; @end #import "UserDefaultManager.h" @implementation UserDefaultManager { NSUserDefaults *_userDefaults; } //Constructor Injection - (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults { self = [super init]; if(self) { _userDefaults = userDefaults; } return self; } - (void)registerLeetInteger { [_userDefaults setInteger:1337 forKey:@"leet"]; } @end
Coding Example DI: Method Injection #import <Foundation/Foundation.h> @interface UserDefaultManager :
NSObject - (void)registerLeetIntegerOnUserDefaults:(NSUserDefaults *)userDefaults; @end #import "UserDefaultManager.h" @implementation UserDefaultManager //Method Injection - (void)registerLeetIntegerOnUserDefaults:(NSUserDefaults *)userDefaults { [userDefaults setInteger:1337 forKey:@"leet"]; } @end
Coding Example DI: Property Injection #import <Foundation/Foundation.h> @interface UserDefaultManager :
NSObject //Property Injection @property (nonatomic, strong) NSUserDefaults *userDefaults; - (void)registerLeetInteger; @end #import "UserDefaultManager.h" @implementation UserDefaultManager - (void)registerLeetInteger { [self.userDefaults setInteger:1337 forKey:@"leet"]; } @end
MVVM
MVC
MASSIVE View Controller
View Controller View Model MVVM View Controller View Model View
Model
Unit Testing frameworks & code coverage
OCMock
Coding Example OCMock: Mocking Class mock OCMClassMock([SomeClass class]); Protocol mock
OCMProtocolMock(@protocol(SomeProtocol)); Strict class & protocol mock OCMStrictClassMock([SomeObject class]); OCMStrictProtocolMock(@protocol(SomeProtocol)); Partial mock OCMPartialMock(anObject); Observer mock OCMObserverMock()
Coding Example OCMock: Stubbing OCMStub([mock someMethod]).andReturn(anObject); OCMStub([mock someMethodReturningABool]).andReturn(YES); OCMStub([mock someMethod]).andCall(anotherObject,
@selector(aDifferentMethod)); OCMStub([mock someMethod]).andThrow(anException);
Coding Example OCMock: Verification OCMVerify([mock someMethod]);
Coding Example OCMock - (void)populateView:(UIView *)view withData:(id)data { PersonView *personView
= (PersonView *)view; PersonObject *personObject = (PersonObject *)data; [_imageService fetchImageFromURL:personObject.imageURL fallBackImage:[UIImage personFallBackImage] forImageView:personView.personImageView]; } - (void)testPopulateViewWithDataDoesInvokeImageServiceForPersonImageViewWithExpectedFallbackImage { UIImageView *givenImageView = [[UIImageView alloc] init]; OCMExpect(_view.personImageView).andReturn(givenImageView); [_populator populateView:_view withData:_data]; OCMVerify([_imageService fetchImageFromURL:_data.imageURL fallBackImage:[UIImage personFallBackImage] forImageView:givenImageView]); }
OCMockito personal favorite
Coding Example OCMockito: Mocking Class mock mockClass([SomeClass class]); Protocol mock
mockProtocol(@protocol(SomeProtocol)); mockProtocolWithoutOptionals(@protocol( SomeProtocol)); Class & protocol mock mockObjectAndProtocol([SomeObject class], @protocol(SomeProtocol));
Coding Example OCMockito: Stubbing [given([mock someMethod]) willReturn:anObject]; [given([mock aMethodReturningABoolean]) willReturnBool:YES];
Coding Example OCMockito: Verification [verify(mock) someMethod]; [verifyCount(mock, times(1)) someMethod]; [verifyCount(mock,
never()) someMethod];
Coding Example OCMockito - (void)populateView:(UIView *)view withData:(id)data { PersonView *personView
= (PersonView *)view; PersonObject *personObject = (PersonObject *)data; [_imageService fetchImageFromURL:personObject.imageURL fallBackImage:[UIImage personFallBackImage] forImageView:personView.personImageView]; } - (void)testPopulateViewWithDataDoesInvokeImageServiceForPersonImageViewWithExpectedFallbackImage { UIImageView *givenImageView = [[UIImageView alloc] init]; [given(_view.personImageView) willReturn:givenImageView]; [_populator populateView:_view withData:_data]; [verify(_imageService) fetchImageFromURL:_data.imageURL fallBackImage:[UIImage personFallBackImage] forImageView:givenImageView]; }
Expecta
Coding Example Expecta Object matchers .conformsTo(@protocol(SomeProtocol)) .equal(anObject) .beIdenticalTo(anObject) .beNil() .beInstanceOf([SomeClass
class]) Number matchers .beCloseTo(@3) .beGreaterThan(@3) .beGreaterThanOrEqualTo(@3) .beLessThan(@3) .beLessThanOrEqualTo(@3) .beFalsy() .beTruthy()
Coding Example Expecta Text matchers .beginWith(@"someString") .endWith(@"someString") .match(@"regex") Collection matchers
.contain(objectA, objectB) .beSupersetOf(objectA, objectB) .haveCountOf() .beEmpty() Logical matchers .notTo Async matchers .will .willNot .after(2)
Coding Example Expecta - (void)populateView:(UIView *)view withData:(id)data { PersonView *personView
= (PersonView *)view; PersonObject *personObject = (PersonObject *)data; personView.ageLabel.text = personObject.age.stringValue; } - (void)testPopulateViewWithDataDoesPopulateAgeLabelWithAge { UILabel *givenLabel = [[UILabel alloc] init]; OCMExpect(_view.ageLabel).andReturn(givenLabel); [_populator populateView:_view withData:_data]; expect(givenLabel.text).to.equal(_data.age.stringValue); }
OCHamcrest personal favorite
Coding Example OCHamcrest Object matchers conformsTo(@protocol(SomeProtocol)) equalTo(anObject) sameInstance(anObject) hasProperty(@"propertyName", @“propertyValue")
instanceOf([SomeClass class]) Number matchers closeTo(@3) greaterThan(@3) greaterThanOrEqualTo(@3) lessThan(@3) lessThanOrEqualTo(@3) isFalse() isTrue()
Coding Example OCHamcrest Text matchers containsSubstring(@"someString"); startsWith(@"someString"); endsWith(@"someString"); equalToIgnoringCase(@"someString"); Collection
matchers contains(objectA, objectB) hasItems(objectA, objectB) everyItem() isEmpty() Logical matchers isNot() anything() allOf()
Coding Example OCHamcrest - (void)populateView:(UIView *)view withData:(id)data { PersonView *personView
= (PersonView *)view; PersonObject *personObject = (PersonObject *)data; personView.ageLabel.text = personObject.age.stringValue; } - (void)testPopulateViewWithDataDoesPopulateAgeLabelWithAge { UILabel *givenLabel = [[UILabel alloc] init]; [given(_view.ageLabel) willReturn:givenLabel]; [_populator populateView:_view withData:_data]; assertThat(givenLabel.text, is(equalTo(_data.age.stringValue)); }
Specta
Coding Example Specta SpecBegin(_PersonViewPopulator) describe(@"PersonViewPopulator", ^{ __block PersonViewPopulator *_populator; __block
PersonObject *_data; __block PersonView *_view; __block id<ImageService> _imageService; __block NSURL *_imageURL; beforeEach(^{ _imageURL = [[NSURL alloc] initWithString:@"http://www.apple.com"]; _view = OCMClassMock([PersonView class]); _imageService = OCMProtocolMock(@protocol(ImageService)); _populator = [[PersonViewPopulator alloc] initWithImageService:_imageService]; _data = [[PersonObject alloc] initWithName:@"expectedName" imageURL:_imageURL slogan:@"expectedSlogan" location:@"expectedLocation" age:@25]; }); it(@"does invoke image service with expected fallback image", ^{ UIImageView *givenImageView = [[UIImageView alloc] init]; OCMExpect(_view.personImageView).andReturn(givenImageView); [_populator populateView:_view withData:_data]; OCMVerify([_imageService fetchImageFromURL:_data.imageURL fallBackImage:[UIImage personFallBackImage] forImageView:givenImageView]); }); }); SpecEnd
Code coverage live demo
UI Testing
UI testing in Xcode live demo
KIF live demo
Clean Code - Robert C. Martin Test-Driven iOS Development -
Graham Lee Test-Driven Development by Example - Kent Beck
User feedback
A/B testing
None
None
B A
Questions? Joris Dubois Consultant @ AppFoundry
[email protected]
@DuboisJoris