SlideShare uma empresa Scribd logo
1 de 26
Baixar para ler offline
Testing view controllers
with Quick and Nimble
Marcio Klepacz
iOS Engineering @ GetYourGuide - Swift Berlin 2015
Overview
• The Problem
• Tools
• Example
• Conclusion
The Problem
View Controllers
• The place where the user interface connects with the app logic
and model
Controller
ModelView
• One of the pillars of the architecture.
• Sensible code.
• Involuntary change can damage.
Testing View Controllers
• Not easy
• lifecycle managed
by the framework.
• lot’s of states.
😰
Tools
Behaviour Driven
Development (BDD)
BDD BDD+View Controllers
Tests that verify what an
application does are
behavioural tests.
What a view controllers
does rather than how.
Check the behaviour not
pieces of code.
Robust testing.
More readable. More readable tests.
Quick and Nimble
• Quick is a Behaviour-driven development
framework for Swift and Objective-C.
• Inspired by RSpec,Specta, and Ginkgo.
• Nimble is a Matcher Framework also for both
languages.
• Provide more clear expectations.
Example
iOS App: Pony
• PonyTabController:
UITabBarController.
• Responsible for
presenting the app
intro
PonyTabController
public class PonyTabController: UITabBarController {
override public func viewDidAppear(animated: Bool) {
//…
if !appIntroHasBeenPresented {
presentViewController(appIntroViewController,…) {
appIntroViewController.dismissButtonTapHandler = {
appIntroHasBeenPresented = true
self.dismissViewControllerAnimated(true,…)
}
• Check if app intro has been presented ⚠
• Present app intro. ⚠
• Dismiss if handler is called. ⚠
Testing: Present app intro ⚠
import Quick
import Nimble
class PonyTabBarControllerSpec: QuickSpec {
override func spec() {
describe(“.viewDidAppear"){
context("when app intro had never been dismissed"){
it("should be presented”){
expect(tabBarController.presentedViewController)
.toEventually(beAnInstanceOf(AppIntroViewController))
}
}
}
//…
• Pre-conditions are still missing. ⚠
• The object under test is not being invoked. ⚠
Testing: Present app intro ⚠
import Pony
//…
var tabBarController: PonyTabController!
describe(".viewDidAppear"){
context("when app intro had never been dismissed"){
beforeEach {
// 1 Arrange:
tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController
// 2 Act:
let _ = tabBarController.view
}
it("should be presented”){
// 3 Assert:
expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…))
}
}
}
} 1. Pre-conditions. ✅
2. The object under test is being invoked. ✅
3. Asserting. ⚠
"Arrange-Act-Assert"
• Pattern for arranging and formatting code in
Tests methods.
• Benefit:
• Clearly separates what is being tested from
the setup and verification steps.
Testing: Present app intro ⚠
import Pony
//…
var tabBarController: PonyTabController!
describe(".viewDidAppear"){
context("when app intro had never been dismissed"){
beforeEach {
// 1 Arrange:
tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController
// 2 Act:
let _ = tabBarController.view
}
it("should be presented”){
// 3 Assert:
expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…))
}
}
}
} 1. Pre-conditions. ✅
2. The object under test is being invoked. ✅
3. Asserting. ⚠
Testing: Present app intro ✅
PonyTabController: UITabBarController {
override public func viewDidAppear(animated: Bool) {
//…
presentViewController(appIntroViewController,…) {
}
//…
Warning: Attempt to present <AppIntroViewController: 0x1e56e0a0> on
<PonyTabController: 0x1ec3e000>
whose view is not in the window hierarchy!
Testing: Present app intro ✅
import Pony
//…
var tabBarController: PonyTabController!
describe(".viewDidAppear"){
context("when app intro had never been dismissed"){
beforeEach {
// 1 Arrange:
tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController
// 2 Act:
UIApplication.sharedApplication().keyWindow?.rootViewController = tabBarController
it("should be presented”){
// 3 Assert:
expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…))
}
}
}
}
1. Pre-conditions. ✅
2. The object under test is being invoked. ✅
3. Asserting. ✅
Testing: Dismiss app intro ⚠
//…
context("when app intro had never been dismissed”){
//…
context("and dismiss button was tapped") {
beforeEach {
// Arrange:
appIntroHasBeenPresented = false
// Act:
tabBarController.beginAppearanceTransition(true, animated: false)
tabBarController.endAppearanceTransition()
var appIntroViewController = tabBarController.presentedViewController as! AppIntroViewController
appIntroViewController.dismissButton!
.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
}
it("should dismiss app intro"){
// Assert:
expect(tabBarController.presentedViewController).toEventually(beNil())
}
//…
}
• Another context.
• beginAppearanceTransition: will trigger viewWillAppear.
• endAppearanceTransition: will trigger viewDidAppear.
• sendActionsForControlEvents: simulate tap on the dismiss button
Testing: Dismiss app intro ✅
//…
context("when app intro had never been dismissed”){
//…
context("and dismiss button was tapped") {
beforeEach {
// Arrange:
appIntroHasBeenPresented = false
// Act:
tabBarController.beginAppearanceTransition(true, animated: false)
tabBarController.endAppearanceTransition()
var appIntroViewController = tabBarController.presentedViewController as! AppIntroViewController
appIntroViewController.dismissButton!
.sendActionsForControlEvents(UIControlEvents.TouchUpInside)
}
it("should set appIntroHasBeenPresented to true""){
// Assert:
expect(appIntroHasBeenPresented).to(beTrue())
}
it("should dismiss app intro"){
// Assert:
expect(tabBarController.presentedViewController).toEventually(beNil())
}
//…
}
• Set app intro presented to be true. ✅
• Will dismiss if the button tap handler is called. ✅
Extra
//…
waitUntil { done in
tabBarController.dismissViewControllerAnimated(false) {
done()
}
}
}
//…
waitUntil { done in
NSThread.sleepForTimeInterval(0.5)
done()
}
//…
• waitUntil is a function provided by Nimble where you can execute
something inside it closure and call done() when is ready.
• Useful when waiting for a callback.
Tested ✅
• Verifying the app intro will be presented if it had
never been dismissed. ✅
• Set app intro presented to be true. ✅
• Will dismiss if the button tap handler is called. ✅
//…
it("should be presented”){
expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…))
}
//…
it("should dismiss app intro"){
expect(tabBarController.presentedViewController).toEventually(beNil())
}
it("should set appIntroHasBeenPresented to true"){
expect(appIntroHasBeenPresented).to(beTrue())
}
//…
Conclusion
Conclusion
• BDD + Quick and Nimble can help you get more
meaningful tests for view controllers.
• There is a lifecycle that must be followed, i.e: you
can’t present a V.C. if there another already being
presented or the view is not part of the hierarchy.
• UIKit provide public methods that can help.
• Don’t create massive view controllers.
Questions ?
References
• https://github.com/Quick/Quick
• http://realm.io/news/testing-in-swift/
• http://www.slideshare.net/bgesiak/everything-you-never-
wanted
• http://c2.com/cgi/wiki?ArrangeActAssert

Mais conteúdo relacionado

Mais procurados

Mais procurados (18)

Introduction to ReactJS and Redux
Introduction to ReactJS and ReduxIntroduction to ReactJS and Redux
Introduction to ReactJS and Redux
 
Deep Dive into React Hooks
Deep Dive into React HooksDeep Dive into React Hooks
Deep Dive into React Hooks
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
 
New improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, HelsinkiNew improvements for web developers - frontend.fi, Helsinki
New improvements for web developers - frontend.fi, Helsinki
 
Adventures In JavaScript Testing
Adventures In JavaScript TestingAdventures In JavaScript Testing
Adventures In JavaScript Testing
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Simplified Android Development with Simple-Stack
Simplified Android Development with Simple-StackSimplified Android Development with Simple-Stack
Simplified Android Development with Simple-Stack
 
04 Advanced Javascript
04 Advanced Javascript04 Advanced Javascript
04 Advanced Javascript
 
Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)
 
UI 모듈화로 워라밸 지키기
UI 모듈화로 워라밸 지키기UI 모듈화로 워라밸 지키기
UI 모듈화로 워라밸 지키기
 
Adding a modern twist to legacy web applications
Adding a modern twist to legacy web applicationsAdding a modern twist to legacy web applications
Adding a modern twist to legacy web applications
 
Reliable Javascript
Reliable Javascript Reliable Javascript
Reliable Javascript
 
Testing Ember Apps: Managing Dependency
Testing Ember Apps: Managing DependencyTesting Ember Apps: Managing Dependency
Testing Ember Apps: Managing Dependency
 
State management in android applications
State management in android applicationsState management in android applications
State management in android applications
 
Swift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medicaSwift Montevideo Meetup - iPhone, una herramienta medica
Swift Montevideo Meetup - iPhone, una herramienta medica
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
Selenide alternative in Python - Introducing Selene [SeleniumCamp 2016]
 
React lecture
React lectureReact lecture
React lecture
 

Semelhante a Testing view controllers with Quick and Nimble

Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
Mahmoud Hamed Mahmoud
 
iOS app dev Training - Session1
iOS app dev Training - Session1iOS app dev Training - Session1
iOS app dev Training - Session1
Hussain Behestee
 
The Spring Framework: A brief introduction to Inversion of Control
The Spring Framework:A brief introduction toInversion of ControlThe Spring Framework:A brief introduction toInversion of Control
The Spring Framework: A brief introduction to Inversion of Control
VisualBee.com
 

Semelhante a Testing view controllers with Quick and Nimble (20)

Introduction of Xcode
Introduction of XcodeIntroduction of Xcode
Introduction of Xcode
 
Android Wear: A Developer's Perspective
Android Wear: A Developer's PerspectiveAndroid Wear: A Developer's Perspective
Android Wear: A Developer's Perspective
 
Testing C# and ASP.net using Ruby
Testing C# and ASP.net using RubyTesting C# and ASP.net using Ruby
Testing C# and ASP.net using Ruby
 
Advance UIAutomator : Documentaion
Advance UIAutomator : DocumentaionAdvance UIAutomator : Documentaion
Advance UIAutomator : Documentaion
 
Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development Windows Store app using XAML and C#: Enterprise Product Development
Windows Store app using XAML and C#: Enterprise Product Development
 
Leaving Interface Builder Behind
Leaving Interface Builder BehindLeaving Interface Builder Behind
Leaving Interface Builder Behind
 
iOS app dev Training - Session1
iOS app dev Training - Session1iOS app dev Training - Session1
iOS app dev Training - Session1
 
Commit University - Exploring Angular 2
Commit University - Exploring Angular 2Commit University - Exploring Angular 2
Commit University - Exploring Angular 2
 
Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications  Ember.js - A JavaScript framework for creating ambitious web applications
Ember.js - A JavaScript framework for creating ambitious web applications
 
[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법
 
How React Native, Appium and me made each other shine @ContinuousDeliveryAmst...
How React Native, Appium and me made each other shine @ContinuousDeliveryAmst...How React Native, Appium and me made each other shine @ContinuousDeliveryAmst...
How React Native, Appium and me made each other shine @ContinuousDeliveryAmst...
 
Workshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte IIWorkshop 13: AngularJS Parte II
Workshop 13: AngularJS Parte II
 
The Spring Framework: A brief introduction to Inversion of Control
The Spring Framework:A brief introduction toInversion of ControlThe Spring Framework:A brief introduction toInversion of Control
The Spring Framework: A brief introduction to Inversion of Control
 
mean stack
mean stackmean stack
mean stack
 
Declarative presentations UIKonf
Declarative presentations UIKonfDeclarative presentations UIKonf
Declarative presentations UIKonf
 
Will your code blend? : Toronto Code Camp 2010 : Barry Gervin
Will your code blend? : Toronto Code Camp 2010 : Barry GervinWill your code blend? : Toronto Code Camp 2010 : Barry Gervin
Will your code blend? : Toronto Code Camp 2010 : Barry Gervin
 
Javascript tdd byandreapaciolla
Javascript tdd byandreapaciollaJavascript tdd byandreapaciolla
Javascript tdd byandreapaciolla
 
Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015
 
AngularJs Crash Course
AngularJs Crash CourseAngularJs Crash Course
AngularJs Crash Course
 
01 startoff angularjs
01 startoff angularjs01 startoff angularjs
01 startoff angularjs
 

Último

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Último (20)

HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 

Testing view controllers with Quick and Nimble

  • 1. Testing view controllers with Quick and Nimble Marcio Klepacz iOS Engineering @ GetYourGuide - Swift Berlin 2015
  • 2. Overview • The Problem • Tools • Example • Conclusion
  • 4. View Controllers • The place where the user interface connects with the app logic and model Controller ModelView
  • 5. • One of the pillars of the architecture. • Sensible code. • Involuntary change can damage.
  • 6. Testing View Controllers • Not easy • lifecycle managed by the framework. • lot’s of states. 😰
  • 8. Behaviour Driven Development (BDD) BDD BDD+View Controllers Tests that verify what an application does are behavioural tests. What a view controllers does rather than how. Check the behaviour not pieces of code. Robust testing. More readable. More readable tests.
  • 9. Quick and Nimble • Quick is a Behaviour-driven development framework for Swift and Objective-C. • Inspired by RSpec,Specta, and Ginkgo. • Nimble is a Matcher Framework also for both languages. • Provide more clear expectations.
  • 11. iOS App: Pony • PonyTabController: UITabBarController. • Responsible for presenting the app intro
  • 12. PonyTabController public class PonyTabController: UITabBarController { override public func viewDidAppear(animated: Bool) { //… if !appIntroHasBeenPresented { presentViewController(appIntroViewController,…) { appIntroViewController.dismissButtonTapHandler = { appIntroHasBeenPresented = true self.dismissViewControllerAnimated(true,…) } • Check if app intro has been presented ⚠ • Present app intro. ⚠ • Dismiss if handler is called. ⚠
  • 13. Testing: Present app intro ⚠ import Quick import Nimble class PonyTabBarControllerSpec: QuickSpec { override func spec() { describe(“.viewDidAppear"){ context("when app intro had never been dismissed"){ it("should be presented”){ expect(tabBarController.presentedViewController) .toEventually(beAnInstanceOf(AppIntroViewController)) } } } //… • Pre-conditions are still missing. ⚠ • The object under test is not being invoked. ⚠
  • 14. Testing: Present app intro ⚠ import Pony //… var tabBarController: PonyTabController! describe(".viewDidAppear"){ context("when app intro had never been dismissed"){ beforeEach { // 1 Arrange: tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController // 2 Act: let _ = tabBarController.view } it("should be presented”){ // 3 Assert: expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…)) } } } } 1. Pre-conditions. ✅ 2. The object under test is being invoked. ✅ 3. Asserting. ⚠
  • 15. "Arrange-Act-Assert" • Pattern for arranging and formatting code in Tests methods. • Benefit: • Clearly separates what is being tested from the setup and verification steps.
  • 16. Testing: Present app intro ⚠ import Pony //… var tabBarController: PonyTabController! describe(".viewDidAppear"){ context("when app intro had never been dismissed"){ beforeEach { // 1 Arrange: tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController // 2 Act: let _ = tabBarController.view } it("should be presented”){ // 3 Assert: expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…)) } } } } 1. Pre-conditions. ✅ 2. The object under test is being invoked. ✅ 3. Asserting. ⚠
  • 17. Testing: Present app intro ✅ PonyTabController: UITabBarController { override public func viewDidAppear(animated: Bool) { //… presentViewController(appIntroViewController,…) { } //… Warning: Attempt to present <AppIntroViewController: 0x1e56e0a0> on <PonyTabController: 0x1ec3e000> whose view is not in the window hierarchy!
  • 18. Testing: Present app intro ✅ import Pony //… var tabBarController: PonyTabController! describe(".viewDidAppear"){ context("when app intro had never been dismissed"){ beforeEach { // 1 Arrange: tabBarController = storyboard.instantiateInitialViewController() as! PonyTabController // 2 Act: UIApplication.sharedApplication().keyWindow?.rootViewController = tabBarController it("should be presented”){ // 3 Assert: expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…)) } } } } 1. Pre-conditions. ✅ 2. The object under test is being invoked. ✅ 3. Asserting. ✅
  • 19. Testing: Dismiss app intro ⚠ //… context("when app intro had never been dismissed”){ //… context("and dismiss button was tapped") { beforeEach { // Arrange: appIntroHasBeenPresented = false // Act: tabBarController.beginAppearanceTransition(true, animated: false) tabBarController.endAppearanceTransition() var appIntroViewController = tabBarController.presentedViewController as! AppIntroViewController appIntroViewController.dismissButton! .sendActionsForControlEvents(UIControlEvents.TouchUpInside) } it("should dismiss app intro"){ // Assert: expect(tabBarController.presentedViewController).toEventually(beNil()) } //… } • Another context. • beginAppearanceTransition: will trigger viewWillAppear. • endAppearanceTransition: will trigger viewDidAppear. • sendActionsForControlEvents: simulate tap on the dismiss button
  • 20. Testing: Dismiss app intro ✅ //… context("when app intro had never been dismissed”){ //… context("and dismiss button was tapped") { beforeEach { // Arrange: appIntroHasBeenPresented = false // Act: tabBarController.beginAppearanceTransition(true, animated: false) tabBarController.endAppearanceTransition() var appIntroViewController = tabBarController.presentedViewController as! AppIntroViewController appIntroViewController.dismissButton! .sendActionsForControlEvents(UIControlEvents.TouchUpInside) } it("should set appIntroHasBeenPresented to true""){ // Assert: expect(appIntroHasBeenPresented).to(beTrue()) } it("should dismiss app intro"){ // Assert: expect(tabBarController.presentedViewController).toEventually(beNil()) } //… } • Set app intro presented to be true. ✅ • Will dismiss if the button tap handler is called. ✅
  • 21. Extra //… waitUntil { done in tabBarController.dismissViewControllerAnimated(false) { done() } } } //… waitUntil { done in NSThread.sleepForTimeInterval(0.5) done() } //… • waitUntil is a function provided by Nimble where you can execute something inside it closure and call done() when is ready. • Useful when waiting for a callback.
  • 22. Tested ✅ • Verifying the app intro will be presented if it had never been dismissed. ✅ • Set app intro presented to be true. ✅ • Will dismiss if the button tap handler is called. ✅ //… it("should be presented”){ expect(tabBarController.presentedViewController).toEventually(beAnInstanceOf(AppIntro…)) } //… it("should dismiss app intro"){ expect(tabBarController.presentedViewController).toEventually(beNil()) } it("should set appIntroHasBeenPresented to true"){ expect(appIntroHasBeenPresented).to(beTrue()) } //…
  • 24. Conclusion • BDD + Quick and Nimble can help you get more meaningful tests for view controllers. • There is a lifecycle that must be followed, i.e: you can’t present a V.C. if there another already being presented or the view is not part of the hierarchy. • UIKit provide public methods that can help. • Don’t create massive view controllers.
  • 26. References • https://github.com/Quick/Quick • http://realm.io/news/testing-in-swift/ • http://www.slideshare.net/bgesiak/everything-you-never- wanted • http://c2.com/cgi/wiki?ArrangeActAssert