SlideShare a Scribd company logo
1 of 37
Vodafone Proprietary classified as C2 - Internal
Unit Testing
and Why it Matters
Yahya Saddiq
1 February 2020
Vodafone Proprietary classified as C2 - Internal
2
Hello!
I am Yahya Saddiq, hands-on iOS Lead, _VOIS
at Vodafone.
A father of two, fitness enthusiast and coding
is my passion.
You can find me on LinkedIn.
Vodafone Proprietary classified as C2 - Internal
The Beginning
2 February 20203
• Unit Testing is really important to anyone who is getting started in software
development, whether you’ve just discovered it, self teaching or going to school.
• Even if you’ve got yourself into new job, may be you haven’t been exposed to it yet
cause maybe your organization doesn’t do that.
Vodafone Proprietary classified as C2 - Internal
The Beginning
2 February 20204
• It’s really important to learn it from the beginning cause you never know at what
point at your career or job interview ask you about unit testing and currently
that’s inevitable.
• It’s really important to have the conceptual ideas down your head and being able
to explain it to someone.
Unit Testing is Awesome
😎
Vodafone Proprietary classified as C2 - Internal
What is Unit Testing?
2 February 20205
Vodafone Proprietary classified as C2 - Internal
What is Unit Testing?
2 February 20206
Vodafone Proprietary classified as C2 - Internal
What is Unit Testing?
2 February 20207
• Unit testing helps you to find failures and embarrassing mistakes from being
introduced into your production app
• Helps you have a software that actually works reliably.
• Unit Testing is a White Box testing
Vodafone Proprietary classified as C2 - Internal
What is Unit Testing?
2 February 20208
• The purpose is to validate that each unit of the software code performs as
expected.
• Unit Testing is done during the development of an application by you (developers).
• Unit Tests isolate a section of code and verify its correctness.
• A unit may be an individual
– Function
– Method
– Procedure
– Module
– or Object.
Vodafone Proprietary classified as C2 - Internal
Why We Should Do it?
2 February 20209
• We write unit tests, because we want our code to work and to keep it working.
• Unit tests are a great way to write better code.
• Tests help you find most of the bugs early on in the process.
• More importantly, writing code in a test-based development mindset helps you write
modular code that’s easy to maintain.
Easy to test code,
is easy to maintain and debug code.
Vodafone Proprietary classified as C2 - Internal
Why We Should Do it?
2 February 202010
When it comes to testing, there’s good news, and bad news.
• The bad news is that there can be disadvantages to unit tests.
– More code
– More to maintain
– No silver bullet
– Takes longer
Vodafone Proprietary classified as C2 - Internal
Why We Should Do it?
2 February 202011
Although there is no silver bullet, there is a silver lining.
• Testing has the following advantages
– Protection against regression
– Less coupled code
– Confidence
– Quick feedback
– Focus
– Refactoring
– Executable documentation
Maximizes laziness
😴
Vodafone Proprietary classified as C2 - Internal
How The Process Works in Real Software
World?
2 February 202012
Vodafone Proprietary classified as C2 - Internal
The 5 characteristics of Unit Testing
2 February 202013
•Fast.
•Independent/Isolated.
•Repeatable.
•Self-validating.
•Timely
Following the FIRST principles,
keeps your tests clear and helpful.
Vodafone Proprietary classified as C2 - Internal
A simple gallery app
2 February 202014
We are going to test a simple app, in which:
– The app fetches popular photos from 500px API and lists photos in
a UITableView.
– Each cell in the table view shows a title, a description and the
created date of a photo.
– Users are not allowed to click photos which are not labeled
for_sale.
Vodafone Proprietary classified as C2 - Internal
A simple gallery app
2 February 202015
• The first screen in the app is called PhotoListViewController,
and this is its the data flow.
• We are going to test:
1. Does APIService work and return valid photos?
2. Does photoListCellViewModel correctly created from a photo
object?
3. Does PhotoListViewModel fetch data from the APIService?
4. Does PhotoListViewModel display an error if the request failed?
5. Does PhotoListViewModel allow the segue if the user presses a “for
sale” photo?
Vodafone Proprietary classified as C2 - Internal
The First Test Case
2 February 202016
Does photoListCellViewModel correctly created from a photo object?
• Create a test class for PhotoListViewModel.
• Let’s give the unit tests an access to the internal types and functions in
MVVMPlayground.
@testable import MVVMPlayground.
• Create a placeholder for a PhotoListViewModel, which is the System Under Test, or
the object this test case class is concerned with testing.
var sut: PhotoListViewModel!
Vodafone Proprietary classified as C2 - Internal
Does photoListCellViewModel correctly
created from a photo object?
2 February 202017
• Create a PhotoListViewModel object at the class level, so all the tests in this test
class can access the SUT object’s properties and methods.
super.setUp()
sut = PhotoListViewModel()
• Before we forget, release the SUT object in tearDown().
sut = nil
super.tearDown()
• Setup and teardown prepare initial state before tests run and perform cleanup after
tests complete.
Vodafone Proprietary classified as C2 - Internal
2 February 202018
// A test method’s name always begins with test, followed by a description of what it tests.
func test_cell_view_model() {
// It’s good practice to format the test into given, when and then sections
// Given: Here, you set up any values needed.
// In this example, today’s date and a dummy photo object are created.
let today = Date()
let photo = Photo(id: 1,
name: "Name",
description: "desc",
created_at: today,
image_url: "url",
for_sale: true,
camera: "camera")
// When: In this section, you’ll execute the code being tested: Call createCellViewModel(photo:).
let cellViewModel = sut!.createCellViewModel(photo: photo)
// Then: This is the section where you’ll assert the result you expect with a message that prints if the test fails.
XCTAssertEqual(cellViewModel.descText, "(photo.camera!) - (photo.description!)")
}
Vodafone Proprietary classified as C2 - Internal
Debugging a Test
2 February 202019
• To cause a test failure, let’s change desc join character to +
• In the Breakpoint navigator, add a Test Failure Breakpoint.
– It will stop the test run when a test method posts a failure assertion.
• Run the test, and it should stop at the XCTAssertEqual line with a test failure.
Vodafone Proprietary classified as C2 - Internal
Test Asynchronous Operations
2 February 202020
Does APIService work and return valid photos?
• URLSession methods are asynchronous:
– They return right away, but don’t finish running until later.
– use XCTestExpectation to make your test wait for the asynchronous
operation to complete.
Vodafone Proprietary classified as C2 - Internal
Does APIService work and return valid photos?
2 February 202021
@testable import MVVMPlayground
class APIServiceTests: XCTestCase {
var sut: APIService!
override func setUp() {
super.setUp()
sut = APIService()
}
override func tearDown() {
sut = nil
super.tearDown()
}
}
Vodafone Proprietary classified as C2 - Internal
Does APIService work and return valid photos?
2 February 202022
func test_fetch_popular_photos() {
// Given: Returns an XCTestExpectation object, stored in promise.
// The description parameter describes what you expect to happen.
let promise = XCTestExpectation(description: "Fetch popular photos
completed")
// When
sut.fetchPopularPhoto(complete: { (photos, error) in
// Then
guard error == nil,
let photos = photos else {
if let errorDesc = error?.rawValue {
XCTFail("Error: (errorDesc)")
}
return
}
XCTAssertEqual(photos.count, 20)
for photo in photos {
XCTAssertNotNil(photo.id)
}
// Call this in the success condition closure of the
asynchronous method’s completion handler to flag that the expectation
has been met.
promise.fulfill()
})
// Keeps the test running until all expectations are fulfilled, or
the timeout interval ends, whichever happens first.
wait(for: [promise], timeout: 3.1)
}
Vodafone Proprietary classified as C2 - Internal
Fail Fast
2 February 202023
• Failure hurts, but it doesn’t have to
take forever.
• Let’s update the file name to test a
failure and run the test.
• Now, Let’s improve it and make the
test fail faster by changing the
assumption.
• Run the test. It should now take about
a second to fail.
func test_fetch_popular_photos_completes() {
// Given
let promise = XCTestExpectation(description: "Fetch popular
photos completed")
var responseError: Error?
var responsePhotos: [Photo]?
// When
sut.fetchPopularPhoto(complete: { (photos, error) in
responseError = error
responsePhotos = photos
promise.fulfill()
})
wait(for: [promise], timeout: 3.1)
// Then
XCTAssertNil(responseError)
XCTAssertEqual(responsePhotos?.count, 20)
}
Vodafone Proprietary classified as C2 - Internal
Faking Objects and Interactions
2 February 202024
• Asynchronous tests give you confidence that your code generates correct input to
an asynchronous API.
• Most apps interact with system or library objects — objects you don’t control such
as Alamofire, NotificationCenter or UserDefaults. Tests that interact with these
objects can be slow and unrepeatable, violating two of the FIRST principles.
• Instead, you can fake the interactions by getting input from stubs or by
updating mock objects.
• We should mock all mentioned Black Boxes because unit testing is White Box
testing.
Vodafone Proprietary classified as C2 - Internal
Mocking - Fake Update to Mock Object
2 February 202025
Does PhotoListViewModel fetch data from the APIService?
• We use a technique named Dependency Injection (DI) to design
our PhotoListViewModel.
• The property apiService is a dependency of the PhotoListViewModel.
• In the production environment we assign an APIService object, which connects to a
real server, to the PhotoListViewModel.
• In the test environment, we inject a mock APIService object instead.
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel fetch data from
the APIService?
2 February 202026
@testable import MVVMPlayground
// The mock APIService (APIServiceMock) object doesn’t connect to the real server,
// it’s an object designed only for the test.
// Both APIService and APIServiceMock conform to APIServiceProtocol,
// so that we are able to inject different dependency in different situation.
class APIServiceMock: APIServiceProtocol {
var isFetchPopularPhotoCalled = false
func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) {
isFetchPopularPhotoCalled = true
}
}
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel fetch data from
the APIService?
2 February 202027
• Create an instance of the mock in PhotoListViewModelTests
var apiServiceMock: APIServiceMock!
apiServiceMock = APIServiceMock()
• Inject apiServiceMock to PhotoListViewModel
sut = PhotoListViewModel(apiService: apiServiceMock)
• Add the test case
func test_fetch_photo() {
// When
sut.initFetch()
// Then
XCTAssert(apiServiceMock.isFetchPopularPhotoCalled)
}
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel fetch data from
the APIService?
2 February 202028
• In addition to the behavior test, we also want to see if
the PhotoListViewModel correctly handles networking states.
• By using the DI technique, we are able to simulate the success and failure
networking states by changing the response of the MockAPIService.
• Let’s take a look at the PhotoListViewModel.initFetch():
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel display an error if the request
failed?
2 February 202029
class APIServiceMock: APIServiceProtocol {
var isFetchPopularPhotoCalled = false
var completeClosure: (([Photo]?, APIError?) -> ())!
func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) {
isFetchPopularPhotoCalled = true
// the callback closure is saved to the completeClosure for the later use.
completeClosure = complete
}
// the function call is finished but the escaping closure is still pending.
//The closure won’t be triggered until the fetchSuccess() or the fetchFail(error:) is called.
// Finally, when we call the fetchSuccess() or the fetchFail(error:),
// the PhotoListViewModel receives the response data and continue to finish its jobs.
func fetchSuccess() {
completeClosure([Photo](), nil)
}
func fetchFail(error: APIError?) {
completeClosure(nil, error)
}
}
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel display an error if the request
failed?
2 February 202030
func test_fetch_photo_fail() {
// Given
let error = APIError.permissionDenied
// When
sut.initFetch()
// here’s a trick: we ask the mock to fail the request by calling the fetchFail(error:) function.
apiServiceMock.fetchFail(error: error)
// Then
// assert the alert message of the PhotoListViewModel to see if it handles the error correctly.
XCTAssertEqual(sut.alertMessage, error.rawValue)
}
Vodafone Proprietary classified as C2 - Internal
Stubbing - Fake Input From Stub
2 February 202031
Does PhotoListViewModel allow the segue if the user presses a “for sale” photo?
• The ViewModel receives the user interaction and changes the presentation with
respect to the interaction.
• In MVVM, the user interactions are abstracted into a set of methods such
as userPressed(), userSwipe(), etc.
• Therefore, testing the user interactions is straightforward: we call a certain method
and assert the corresponding property of the ViewModel.
Vodafone Proprietary classified as C2 - Internal
Does PhotoListViewModel allow the segue if the user
presses a “for sale” photo?
2 February 202032
func test_user_press_for_sale_item() {
// Given
let indexPath = IndexPath(row: 0, section: 0)
// When
sut.userPressed(at: indexPath)
// Then
XCTAssertTrue(sut.isAllowSegue)
}
Vodafone Proprietary classified as C2 - Internal
2 February 202033
class APIServiceMock: APIServiceProtocol {
var isFetchPopularPhotoCalled = false
// We create an array, completePhotos, to save the stubs.
// And those stubs will be returns to the PhotoListViewModel once the PhotoListViewModel calls
fetchPopularPhoto(complete:).
var completePhotos: [Photo] = [Photo]()
var completeClosure: (([Photo]?, APIError?) -> ())!
func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) {
isFetchPopularPhotoCalled = true
completeClosure = complete
}
func fetchSuccess() {
completeClosure(completePhotos, nil)
}
func fetchFail(error: APIError?) {
completeClosure(nil, error)
}
}
Does PhotoListViewModel allow the segue if the user
presses a “for sale” photo?
Vodafone Proprietary classified as C2 - Internal
2 February 202034
func test_user_press_for_sale_item() {
// Given
let indexPath = IndexPath(row: 0, section: 0)
// The StubGenerator().stubPhotos() generates couple of photo objects.
// Then we assign the photo objects to the mockAPIService.completePhotos.
apiServiceMock.completePhotos = StubGenerator().stubPhotos()
sut.initFetch()
// When the request finished (mockAPIService.fetchSuccess() is called),
// the PhotoListViewModel will receive those photo stubs via the callback closure.
apiServiceMock.fetchSuccess()
// When
sut.userPressed(at: indexPath)
// Then
XCTAssertTrue(sut.isAllowSegue)
}
Does PhotoListViewModel allow the segue if the user
presses a “for sale” photo?
Vodafone Proprietary classified as C2 - Internal
Code coverage
2 February 202035
• The code coverage tool tells you what app code is actually being run by your tests,
so you know what parts of the app code aren’t (yet) tested.
• To enable code coverage, edit the scheme’s Test action and check the Gather
coverage for check box under the Options tab.
• Run all tests (Command-U), then open the Report navigator (Command-9).
Select Coverage under the top item in that list:
• Research shows that 80% is best cost-efficient code coverage.
Vodafone Proprietary classified as C2 - Internal
Do's and Don'ts
2 February 202036
• Verify One Concern Per Test Method
– A concern is a single end result: a return value or change to app state.
– if the first assert fails, does it matter what happens to the next one?
– If yes, you must split the test into smaller ones.
• Control Side-Effects
– When we change global app data from our test, this indirectly affects the whole test suite.
– To prevent this from happening you must cleanup before and after each test
• Do Not Leak Test Code into Production
– Firstly, do not weaken encapsulation for the purpose of testing.
– It’s either a flaw in the app design or you might be testing too much.
– Secondly, do not put logic into production code, only to support testing.
– Changes in your test code should not affect the production.
Vodafone Proprietary classified as C2 - Internal
2 February 202037
Recap
• We used Unit Test to check:
– If APIService works and returns valid photos.
– If photoListCellViewModel correctly created from a photo object.
– If the SUT correctly interacts with the APIService.
– If the SUT handles the error state correctly.
– If the SUT handles the user interaction correctly.
• Now, you are able to use the knowledge you learned to write more test cases:
– The loading animation should start when the network request starts.
– The loading animation should stop when the request completes.
– The table view should render correctly.
– It should display error message when user press on the photo that is not for sale.

More Related Content

Similar to Unit Testing and Why it Matters

Software Project Proposal- Result Analysis Tool
Software Project Proposal- Result Analysis ToolSoftware Project Proposal- Result Analysis Tool
Software Project Proposal- Result Analysis ToolMinhas Kamal
 
Quality Assurance Guidelines
Quality Assurance GuidelinesQuality Assurance Guidelines
Quality Assurance GuidelinesTim Stribos
 
Quality Assurance Guidelines for Mobile App Development
Quality Assurance Guidelines for Mobile App DevelopmentQuality Assurance Guidelines for Mobile App Development
Quality Assurance Guidelines for Mobile App DevelopmentMoqod
 
Test & behavior driven development
Test & behavior driven developmentTest & behavior driven development
Test & behavior driven developmentTristan Libersat
 
How to feature flag and run experiments in iOS and Android
How to feature flag and run experiments in iOS and AndroidHow to feature flag and run experiments in iOS and Android
How to feature flag and run experiments in iOS and AndroidOptimizely
 
Tutorial test driven development with Visual Studio 2012
Tutorial test driven development with Visual Studio 2012Tutorial test driven development with Visual Studio 2012
Tutorial test driven development with Visual Studio 2012Hong Le Van
 
Info manual testing questions
Info manual testing questionsInfo manual testing questions
Info manual testing questionsSandeep
 
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoft
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoftEngineering Student MuleSoft Meetup#4 - API Testing With MuleSoft
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoftJitendra Bafna
 
Manual testing interview questions by infotech
Manual testing interview questions by infotech Manual testing interview questions by infotech
Manual testing interview questions by infotech suhasreddy1
 
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01Anshuman Rai
 
The Broken Promise of Test Automation: Why are we still hand-cranking tests?
The Broken Promise of Test Automation: Why are we still hand-cranking tests?The Broken Promise of Test Automation: Why are we still hand-cranking tests?
The Broken Promise of Test Automation: Why are we still hand-cranking tests?Curiosity Software Ireland
 
zaid ppt.pptx
zaid ppt.pptxzaid ppt.pptx
zaid ppt.pptxaasim40
 
Acceptance Test Driven Development
Acceptance Test Driven DevelopmentAcceptance Test Driven Development
Acceptance Test Driven DevelopmentAmir Barylko
 
Accelerate Your Delivery Pipeline with Continuous Testing
Accelerate Your Delivery Pipeline with Continuous TestingAccelerate Your Delivery Pipeline with Continuous Testing
Accelerate Your Delivery Pipeline with Continuous TestingSmartBear
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosFlutter Agency
 
Manual testing interview questions
Manual testing interview questionsManual testing interview questions
Manual testing interview questionsBABAR MANZAR
 
Utsha guha cocoa:swift-exp5.9yr
Utsha guha cocoa:swift-exp5.9yrUtsha guha cocoa:swift-exp5.9yr
Utsha guha cocoa:swift-exp5.9yrUtsha Guha
 
Bridging the communication Gap & Continuous Delivery
Bridging the communication Gap & Continuous DeliveryBridging the communication Gap & Continuous Delivery
Bridging the communication Gap & Continuous Deliverymasoodjan
 

Similar to Unit Testing and Why it Matters (20)

Software Project Proposal- Result Analysis Tool
Software Project Proposal- Result Analysis ToolSoftware Project Proposal- Result Analysis Tool
Software Project Proposal- Result Analysis Tool
 
Quality Assurance Guidelines
Quality Assurance GuidelinesQuality Assurance Guidelines
Quality Assurance Guidelines
 
Quality Assurance Guidelines for Mobile App Development
Quality Assurance Guidelines for Mobile App DevelopmentQuality Assurance Guidelines for Mobile App Development
Quality Assurance Guidelines for Mobile App Development
 
Test & behavior driven development
Test & behavior driven developmentTest & behavior driven development
Test & behavior driven development
 
How to feature flag and run experiments in iOS and Android
How to feature flag and run experiments in iOS and AndroidHow to feature flag and run experiments in iOS and Android
How to feature flag and run experiments in iOS and Android
 
Tutorial test driven development with Visual Studio 2012
Tutorial test driven development with Visual Studio 2012Tutorial test driven development with Visual Studio 2012
Tutorial test driven development with Visual Studio 2012
 
Bdd and spec flow
Bdd and spec flowBdd and spec flow
Bdd and spec flow
 
Info manual testing questions
Info manual testing questionsInfo manual testing questions
Info manual testing questions
 
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoft
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoftEngineering Student MuleSoft Meetup#4 - API Testing With MuleSoft
Engineering Student MuleSoft Meetup#4 - API Testing With MuleSoft
 
Dev box testing.pdf
Dev box testing.pdfDev box testing.pdf
Dev box testing.pdf
 
Manual testing interview questions by infotech
Manual testing interview questions by infotech Manual testing interview questions by infotech
Manual testing interview questions by infotech
 
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01
Manualtestinginterviewquestionbyinfotech 100901071035-phpapp01
 
The Broken Promise of Test Automation: Why are we still hand-cranking tests?
The Broken Promise of Test Automation: Why are we still hand-cranking tests?The Broken Promise of Test Automation: Why are we still hand-cranking tests?
The Broken Promise of Test Automation: Why are we still hand-cranking tests?
 
zaid ppt.pptx
zaid ppt.pptxzaid ppt.pptx
zaid ppt.pptx
 
Acceptance Test Driven Development
Acceptance Test Driven DevelopmentAcceptance Test Driven Development
Acceptance Test Driven Development
 
Accelerate Your Delivery Pipeline with Continuous Testing
Accelerate Your Delivery Pipeline with Continuous TestingAccelerate Your Delivery Pipeline with Continuous Testing
Accelerate Your Delivery Pipeline with Continuous Testing
 
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex ScenariosUnit Testing in Flutter - From Workflow Essentials to Complex Scenarios
Unit Testing in Flutter - From Workflow Essentials to Complex Scenarios
 
Manual testing interview questions
Manual testing interview questionsManual testing interview questions
Manual testing interview questions
 
Utsha guha cocoa:swift-exp5.9yr
Utsha guha cocoa:swift-exp5.9yrUtsha guha cocoa:swift-exp5.9yr
Utsha guha cocoa:swift-exp5.9yr
 
Bridging the communication Gap & Continuous Delivery
Bridging the communication Gap & Continuous DeliveryBridging the communication Gap & Continuous Delivery
Bridging the communication Gap & Continuous Delivery
 

Recently uploaded

KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....kzayra69
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 

Recently uploaded (20)

KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....What are the key points to focus on before starting to learn ETL Development....
What are the key points to focus on before starting to learn ETL Development....
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 

Unit Testing and Why it Matters

  • 1. Vodafone Proprietary classified as C2 - Internal Unit Testing and Why it Matters Yahya Saddiq 1 February 2020
  • 2. Vodafone Proprietary classified as C2 - Internal 2 Hello! I am Yahya Saddiq, hands-on iOS Lead, _VOIS at Vodafone. A father of two, fitness enthusiast and coding is my passion. You can find me on LinkedIn.
  • 3. Vodafone Proprietary classified as C2 - Internal The Beginning 2 February 20203 • Unit Testing is really important to anyone who is getting started in software development, whether you’ve just discovered it, self teaching or going to school. • Even if you’ve got yourself into new job, may be you haven’t been exposed to it yet cause maybe your organization doesn’t do that.
  • 4. Vodafone Proprietary classified as C2 - Internal The Beginning 2 February 20204 • It’s really important to learn it from the beginning cause you never know at what point at your career or job interview ask you about unit testing and currently that’s inevitable. • It’s really important to have the conceptual ideas down your head and being able to explain it to someone. Unit Testing is Awesome 😎
  • 5. Vodafone Proprietary classified as C2 - Internal What is Unit Testing? 2 February 20205
  • 6. Vodafone Proprietary classified as C2 - Internal What is Unit Testing? 2 February 20206
  • 7. Vodafone Proprietary classified as C2 - Internal What is Unit Testing? 2 February 20207 • Unit testing helps you to find failures and embarrassing mistakes from being introduced into your production app • Helps you have a software that actually works reliably. • Unit Testing is a White Box testing
  • 8. Vodafone Proprietary classified as C2 - Internal What is Unit Testing? 2 February 20208 • The purpose is to validate that each unit of the software code performs as expected. • Unit Testing is done during the development of an application by you (developers). • Unit Tests isolate a section of code and verify its correctness. • A unit may be an individual – Function – Method – Procedure – Module – or Object.
  • 9. Vodafone Proprietary classified as C2 - Internal Why We Should Do it? 2 February 20209 • We write unit tests, because we want our code to work and to keep it working. • Unit tests are a great way to write better code. • Tests help you find most of the bugs early on in the process. • More importantly, writing code in a test-based development mindset helps you write modular code that’s easy to maintain. Easy to test code, is easy to maintain and debug code.
  • 10. Vodafone Proprietary classified as C2 - Internal Why We Should Do it? 2 February 202010 When it comes to testing, there’s good news, and bad news. • The bad news is that there can be disadvantages to unit tests. – More code – More to maintain – No silver bullet – Takes longer
  • 11. Vodafone Proprietary classified as C2 - Internal Why We Should Do it? 2 February 202011 Although there is no silver bullet, there is a silver lining. • Testing has the following advantages – Protection against regression – Less coupled code – Confidence – Quick feedback – Focus – Refactoring – Executable documentation Maximizes laziness 😴
  • 12. Vodafone Proprietary classified as C2 - Internal How The Process Works in Real Software World? 2 February 202012
  • 13. Vodafone Proprietary classified as C2 - Internal The 5 characteristics of Unit Testing 2 February 202013 •Fast. •Independent/Isolated. •Repeatable. •Self-validating. •Timely Following the FIRST principles, keeps your tests clear and helpful.
  • 14. Vodafone Proprietary classified as C2 - Internal A simple gallery app 2 February 202014 We are going to test a simple app, in which: – The app fetches popular photos from 500px API and lists photos in a UITableView. – Each cell in the table view shows a title, a description and the created date of a photo. – Users are not allowed to click photos which are not labeled for_sale.
  • 15. Vodafone Proprietary classified as C2 - Internal A simple gallery app 2 February 202015 • The first screen in the app is called PhotoListViewController, and this is its the data flow. • We are going to test: 1. Does APIService work and return valid photos? 2. Does photoListCellViewModel correctly created from a photo object? 3. Does PhotoListViewModel fetch data from the APIService? 4. Does PhotoListViewModel display an error if the request failed? 5. Does PhotoListViewModel allow the segue if the user presses a “for sale” photo?
  • 16. Vodafone Proprietary classified as C2 - Internal The First Test Case 2 February 202016 Does photoListCellViewModel correctly created from a photo object? • Create a test class for PhotoListViewModel. • Let’s give the unit tests an access to the internal types and functions in MVVMPlayground. @testable import MVVMPlayground. • Create a placeholder for a PhotoListViewModel, which is the System Under Test, or the object this test case class is concerned with testing. var sut: PhotoListViewModel!
  • 17. Vodafone Proprietary classified as C2 - Internal Does photoListCellViewModel correctly created from a photo object? 2 February 202017 • Create a PhotoListViewModel object at the class level, so all the tests in this test class can access the SUT object’s properties and methods. super.setUp() sut = PhotoListViewModel() • Before we forget, release the SUT object in tearDown(). sut = nil super.tearDown() • Setup and teardown prepare initial state before tests run and perform cleanup after tests complete.
  • 18. Vodafone Proprietary classified as C2 - Internal 2 February 202018 // A test method’s name always begins with test, followed by a description of what it tests. func test_cell_view_model() { // It’s good practice to format the test into given, when and then sections // Given: Here, you set up any values needed. // In this example, today’s date and a dummy photo object are created. let today = Date() let photo = Photo(id: 1, name: "Name", description: "desc", created_at: today, image_url: "url", for_sale: true, camera: "camera") // When: In this section, you’ll execute the code being tested: Call createCellViewModel(photo:). let cellViewModel = sut!.createCellViewModel(photo: photo) // Then: This is the section where you’ll assert the result you expect with a message that prints if the test fails. XCTAssertEqual(cellViewModel.descText, "(photo.camera!) - (photo.description!)") }
  • 19. Vodafone Proprietary classified as C2 - Internal Debugging a Test 2 February 202019 • To cause a test failure, let’s change desc join character to + • In the Breakpoint navigator, add a Test Failure Breakpoint. – It will stop the test run when a test method posts a failure assertion. • Run the test, and it should stop at the XCTAssertEqual line with a test failure.
  • 20. Vodafone Proprietary classified as C2 - Internal Test Asynchronous Operations 2 February 202020 Does APIService work and return valid photos? • URLSession methods are asynchronous: – They return right away, but don’t finish running until later. – use XCTestExpectation to make your test wait for the asynchronous operation to complete.
  • 21. Vodafone Proprietary classified as C2 - Internal Does APIService work and return valid photos? 2 February 202021 @testable import MVVMPlayground class APIServiceTests: XCTestCase { var sut: APIService! override func setUp() { super.setUp() sut = APIService() } override func tearDown() { sut = nil super.tearDown() } }
  • 22. Vodafone Proprietary classified as C2 - Internal Does APIService work and return valid photos? 2 February 202022 func test_fetch_popular_photos() { // Given: Returns an XCTestExpectation object, stored in promise. // The description parameter describes what you expect to happen. let promise = XCTestExpectation(description: "Fetch popular photos completed") // When sut.fetchPopularPhoto(complete: { (photos, error) in // Then guard error == nil, let photos = photos else { if let errorDesc = error?.rawValue { XCTFail("Error: (errorDesc)") } return } XCTAssertEqual(photos.count, 20) for photo in photos { XCTAssertNotNil(photo.id) } // Call this in the success condition closure of the asynchronous method’s completion handler to flag that the expectation has been met. promise.fulfill() }) // Keeps the test running until all expectations are fulfilled, or the timeout interval ends, whichever happens first. wait(for: [promise], timeout: 3.1) }
  • 23. Vodafone Proprietary classified as C2 - Internal Fail Fast 2 February 202023 • Failure hurts, but it doesn’t have to take forever. • Let’s update the file name to test a failure and run the test. • Now, Let’s improve it and make the test fail faster by changing the assumption. • Run the test. It should now take about a second to fail. func test_fetch_popular_photos_completes() { // Given let promise = XCTestExpectation(description: "Fetch popular photos completed") var responseError: Error? var responsePhotos: [Photo]? // When sut.fetchPopularPhoto(complete: { (photos, error) in responseError = error responsePhotos = photos promise.fulfill() }) wait(for: [promise], timeout: 3.1) // Then XCTAssertNil(responseError) XCTAssertEqual(responsePhotos?.count, 20) }
  • 24. Vodafone Proprietary classified as C2 - Internal Faking Objects and Interactions 2 February 202024 • Asynchronous tests give you confidence that your code generates correct input to an asynchronous API. • Most apps interact with system or library objects — objects you don’t control such as Alamofire, NotificationCenter or UserDefaults. Tests that interact with these objects can be slow and unrepeatable, violating two of the FIRST principles. • Instead, you can fake the interactions by getting input from stubs or by updating mock objects. • We should mock all mentioned Black Boxes because unit testing is White Box testing.
  • 25. Vodafone Proprietary classified as C2 - Internal Mocking - Fake Update to Mock Object 2 February 202025 Does PhotoListViewModel fetch data from the APIService? • We use a technique named Dependency Injection (DI) to design our PhotoListViewModel. • The property apiService is a dependency of the PhotoListViewModel. • In the production environment we assign an APIService object, which connects to a real server, to the PhotoListViewModel. • In the test environment, we inject a mock APIService object instead.
  • 26. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel fetch data from the APIService? 2 February 202026 @testable import MVVMPlayground // The mock APIService (APIServiceMock) object doesn’t connect to the real server, // it’s an object designed only for the test. // Both APIService and APIServiceMock conform to APIServiceProtocol, // so that we are able to inject different dependency in different situation. class APIServiceMock: APIServiceProtocol { var isFetchPopularPhotoCalled = false func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) { isFetchPopularPhotoCalled = true } }
  • 27. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel fetch data from the APIService? 2 February 202027 • Create an instance of the mock in PhotoListViewModelTests var apiServiceMock: APIServiceMock! apiServiceMock = APIServiceMock() • Inject apiServiceMock to PhotoListViewModel sut = PhotoListViewModel(apiService: apiServiceMock) • Add the test case func test_fetch_photo() { // When sut.initFetch() // Then XCTAssert(apiServiceMock.isFetchPopularPhotoCalled) }
  • 28. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel fetch data from the APIService? 2 February 202028 • In addition to the behavior test, we also want to see if the PhotoListViewModel correctly handles networking states. • By using the DI technique, we are able to simulate the success and failure networking states by changing the response of the MockAPIService. • Let’s take a look at the PhotoListViewModel.initFetch():
  • 29. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel display an error if the request failed? 2 February 202029 class APIServiceMock: APIServiceProtocol { var isFetchPopularPhotoCalled = false var completeClosure: (([Photo]?, APIError?) -> ())! func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) { isFetchPopularPhotoCalled = true // the callback closure is saved to the completeClosure for the later use. completeClosure = complete } // the function call is finished but the escaping closure is still pending. //The closure won’t be triggered until the fetchSuccess() or the fetchFail(error:) is called. // Finally, when we call the fetchSuccess() or the fetchFail(error:), // the PhotoListViewModel receives the response data and continue to finish its jobs. func fetchSuccess() { completeClosure([Photo](), nil) } func fetchFail(error: APIError?) { completeClosure(nil, error) } }
  • 30. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel display an error if the request failed? 2 February 202030 func test_fetch_photo_fail() { // Given let error = APIError.permissionDenied // When sut.initFetch() // here’s a trick: we ask the mock to fail the request by calling the fetchFail(error:) function. apiServiceMock.fetchFail(error: error) // Then // assert the alert message of the PhotoListViewModel to see if it handles the error correctly. XCTAssertEqual(sut.alertMessage, error.rawValue) }
  • 31. Vodafone Proprietary classified as C2 - Internal Stubbing - Fake Input From Stub 2 February 202031 Does PhotoListViewModel allow the segue if the user presses a “for sale” photo? • The ViewModel receives the user interaction and changes the presentation with respect to the interaction. • In MVVM, the user interactions are abstracted into a set of methods such as userPressed(), userSwipe(), etc. • Therefore, testing the user interactions is straightforward: we call a certain method and assert the corresponding property of the ViewModel.
  • 32. Vodafone Proprietary classified as C2 - Internal Does PhotoListViewModel allow the segue if the user presses a “for sale” photo? 2 February 202032 func test_user_press_for_sale_item() { // Given let indexPath = IndexPath(row: 0, section: 0) // When sut.userPressed(at: indexPath) // Then XCTAssertTrue(sut.isAllowSegue) }
  • 33. Vodafone Proprietary classified as C2 - Internal 2 February 202033 class APIServiceMock: APIServiceProtocol { var isFetchPopularPhotoCalled = false // We create an array, completePhotos, to save the stubs. // And those stubs will be returns to the PhotoListViewModel once the PhotoListViewModel calls fetchPopularPhoto(complete:). var completePhotos: [Photo] = [Photo]() var completeClosure: (([Photo]?, APIError?) -> ())! func fetchPopularPhoto(complete: @escaping ([Photo]?, APIError?) -> ()) { isFetchPopularPhotoCalled = true completeClosure = complete } func fetchSuccess() { completeClosure(completePhotos, nil) } func fetchFail(error: APIError?) { completeClosure(nil, error) } } Does PhotoListViewModel allow the segue if the user presses a “for sale” photo?
  • 34. Vodafone Proprietary classified as C2 - Internal 2 February 202034 func test_user_press_for_sale_item() { // Given let indexPath = IndexPath(row: 0, section: 0) // The StubGenerator().stubPhotos() generates couple of photo objects. // Then we assign the photo objects to the mockAPIService.completePhotos. apiServiceMock.completePhotos = StubGenerator().stubPhotos() sut.initFetch() // When the request finished (mockAPIService.fetchSuccess() is called), // the PhotoListViewModel will receive those photo stubs via the callback closure. apiServiceMock.fetchSuccess() // When sut.userPressed(at: indexPath) // Then XCTAssertTrue(sut.isAllowSegue) } Does PhotoListViewModel allow the segue if the user presses a “for sale” photo?
  • 35. Vodafone Proprietary classified as C2 - Internal Code coverage 2 February 202035 • The code coverage tool tells you what app code is actually being run by your tests, so you know what parts of the app code aren’t (yet) tested. • To enable code coverage, edit the scheme’s Test action and check the Gather coverage for check box under the Options tab. • Run all tests (Command-U), then open the Report navigator (Command-9). Select Coverage under the top item in that list: • Research shows that 80% is best cost-efficient code coverage.
  • 36. Vodafone Proprietary classified as C2 - Internal Do's and Don'ts 2 February 202036 • Verify One Concern Per Test Method – A concern is a single end result: a return value or change to app state. – if the first assert fails, does it matter what happens to the next one? – If yes, you must split the test into smaller ones. • Control Side-Effects – When we change global app data from our test, this indirectly affects the whole test suite. – To prevent this from happening you must cleanup before and after each test • Do Not Leak Test Code into Production – Firstly, do not weaken encapsulation for the purpose of testing. – It’s either a flaw in the app design or you might be testing too much. – Secondly, do not put logic into production code, only to support testing. – Changes in your test code should not affect the production.
  • 37. Vodafone Proprietary classified as C2 - Internal 2 February 202037 Recap • We used Unit Test to check: – If APIService works and returns valid photos. – If photoListCellViewModel correctly created from a photo object. – If the SUT correctly interacts with the APIService. – If the SUT handles the error state correctly. – If the SUT handles the user interaction correctly. • Now, you are able to use the knowledge you learned to write more test cases: – The loading animation should start when the network request starts. – The loading animation should stop when the request completes. – The table view should render correctly. – It should display error message when user press on the photo that is not for sale.

Editor's Notes

  1. Unit Tests. These should count for the majority of tests you have for your codebase. They tests the smallest unit of code possible. Normally, only test a single method each. Integration Tests to verify the integration of different parts of separate components of a software system together. This can be integration with a Database, with a Framework, with third party external software systems. At the top is the end-to-end tests which are tests that verifies the end to end workflows of your codebase. They tests the system from the user-action entry point right to the end of the system down to the database level. However, these are typically black-box tests.
  2. More code: In projects with high test coverage it’s possible to have more test code than functional code. More to maintain: When there is more code, there is more to maintain. No silver bullet: Unit tests don’t (and can’t) ensure that your code is free of bugs. Takes longer: Writing tests takes time — time you could spend watching Netflix.
  3. Regression defects: are defects that are introduced when a change is made to the application. It is common for testers to not only test their new feature but also features that existed beforehand in order to verify that previously implemented features still function as expected. Less Coupled: Writing tests for your code will naturally decouple your code, because it would be more difficult to test otherwise. Confidence: You can demonstrate that your code works. Quick feedback: You can use unit tests to quickly validate code that is buried many layers deep in your app navigation — things that are cumbersome to test manually. Focus: Writing tests for micro features keep you focused on the small details.
  4. How this process works in real software world? It works through continuous integration, every time someone commit their code to your code repository you fire all your tests and if even one test fail the entire team get an email with the failure, the cause and the person who should fix it. While both human code reviews and pair programming can be effective in monitoring coding standards, they do not scale as well as automated tools. Not only do tools contain hundreds of rules (that are usually customizable), they can be run frequently and usually without intervention. In a CI environment, a code analysis tool can be run any time a change is made to the repository. Code analysis tool like SonarQube can report complexity metrics like cyclomatic complexity, long methods, long classes, unnecessary verbose code, a poorly named methods/classes/variables. By continuously monitoring and auditing code, your team can stay on track with architectural and coding guidelines.
  5. Fast. It is not uncommon for mature projects to have thousands of unit tests. Unit tests should take very little time to run. Milliseconds. Independent/Isolated. Unit tests are standalone, can be run in isolation, and have no dependencies on any outside factors such as a file system or database. Repeatable. Running a unit test should be consistent with its results, that is, it always returns the same result if you do not change anything in between runs. External data providers or concurrency issues could cause intermittent failures. Self-validating: Tests should be fully automated. The output should be either “pass” or “fail”, rather than rely on a programmer’s interpretation of a log file. Timely. A unit test should not take a disproportionately long time to write compared to the code being tested. If you find testing the code taking a large amount of time compared to writing the code, consider a design that is more testable.
  6. Run the app
  7. The APIService takes the responsibility of the network layer, such as setting up the URL, sending the request, etc. The PhotoListViewModel asks the APIService for photo objects and provides the presentational interfaces for the PhotoListViewController. The PhotoListViewController is a simple View, rendering the visible element according to the data presented by the PhotoListViewModel.
  8. why super.teardown last? This method is called last in case the current class is relying on something that might be nulled out or cleaned up in the superclass.
  9. Run the test by clicking the diamond icon in the gutter or in the Test navigator. This will build and run the app, and the diamond icon will change to a green check mark! Note: To see a full list of XCTestAssertions, go to Apple’s Assertions Listed by Category.
  10. It fails, but it takes the full timeout interval! This is because you assumed the request would always succeed, and that’s where you called promise.fulfill(). Since the request failed, it finished only when the timeout expired.
  11. We don’t create an instance of APIService inside the viewModel (that’s tightly coupled) We pass APIService to viewModel in the class constructor (that’s DI) If you’re not familiar with the idea of dependency injection, feel free to check my talk MVVM with DI on youtube
  12. This is a simple test case. The code snippet shows that when the PhotoListViewModel fetches data, we check if it called the fetchPopularPhoto(complete:) method. By using this technique, we are able to check if PhotoListViewModel calls specified methods for the dependency injection. In other words, we successfully test the behavior of our ViewModel.
  13. explain changes first Now the APIServiceMock is able to simulate any kind of asynchronous request. For example, we are able to assert the state of the ViewModel: state should be loading before fetchSuccess() is called. This is a powerful technique because it mimics an async call, and it could be done immediately.
  14. Run the test Now the APIServiceMock is able to simulate any kind of asynchronous request. For example, we are able to assert the state of the ViewModel: state should be loading before fetchSuccess() is called. This is a powerful technique because it mimics an async call, and it could be done immediately.
  15. Run the test This test case describes a user who presses on the first cell, and we are going to see if the segue is allowed. The problem is, we haven’t fetched any photo yet and the sut is currently in the empty state. So if we trigger the sut.userPressed(at:) at this stage, the out of bounds exception will be raised. We need to grab some data first!
  16. explain changes first
  17. Explain changes first Run the test It should succeed pretty quickly because there isn’t any real network connection! With the help of those stubs, we are able to assert a certain action such as user presses on a specific IndexPath and so on.