SlideShare a Scribd company logo
1 of 77
Download to read offline
How to Write Better Code with Mutation Testing
John Backus - @backus - john@blockscore.com
Talk Outline
Introduction
Talk Outline
Introduction
Improving coverage
Talk Outline
Introduction
Improving coverage
Learning about Ruby and the code you rely on
Line Coverage
Lines of Code Run by Tests Total Lines of Code÷
Mutation Coverage
How much of your code can I change
without breaking your tests?
Mutation Testing by Hand
1 class Gluttons
2 def initialize(twitter_client)
3 @twitter = twitter_client
4 end
5
6 def recent
7 query = @twitter.search('"I really enjoy #pizza"')
8
9 query.first(2).map { |tweet| "@#{tweet.author}" }
10 end
11 end
1 RSpec.describe Gluttons do
2 it 'lists the two most recent gluttonous tweeters' do
3 tweets = [double(author: 'John'), double(author: 'Jane')]
4 gluttons = Gluttons.new(double(search: tweets))
5
6 expect(gluttons.recent).to eql(%w[@John @Jane])
7 end
8 end
1 class Gluttons
2 def recent
3 - query = @twitter.search('"I really enjoy #pizza"')
4 + query = @twitter.search('"I really enjoy #hotdogs"')
1 example, 0 failures
1 class Gluttons
2 def recent
3 - query = @twitter.search('"I really enjoy #pizza"')
4 + query = @twitter.search('')
1 example, 0 failures
1 class Gluttons
2 def recent
3 - query = @twitter.search('"I really enjoy #pizza"')
4 + query = @twitter.search
1 example, 0 failures
1 class Gluttons
2 def recent
3 - query.first(2).map { |tweet| "@#{tweet.author}" }
4 + query.first(1).map { |tweet| "@#{tweet.author}" }
Failure
expected: ["@John", "@Jane"]
got: ["@John"]
1 - query.first(2).map { |tweet| "@#{tweet.author}" }
2 + query.first(3).map { |tweet| "@#{tweet.author}" }
3 end
1 example, 0 failures
Manual Mutation Testing
Tedious
Manual Mutation Testing
Hard to outsmart yourself
1 def recent
2 - query = @twitter.search('"I really enjoy #pizza"')
3 + query = @twitter.search
1 def recent
2 - query = @twitter.search('"I really enjoy #pizza"')
3 + query = @twitter.search(nil)
1 - query.first(2).map { |tweet| "@#{tweet.author}" }
2 + query.last(2).map { |tweet| "@#{tweet.author}" }
3 end
1 - query.first(2).map { |tweet| "@#{tweet.author}" }
2 + query.map { |tweet| "@#{tweet.author}" }
3 end
1 it 'lists the two most recent gluttonous tweeters' do
2 tweets = [
3 double(author: 'John'),
4 double(author: 'Jane'),
5 double(author: 'Devon')
6 ]
7
8 client = double('Client')
9 gluttons = Gluttons.new(client)
10
11 allow(client)
12 .to receive(:search)
13 .with('"I really enjoy #pizza"')
14 .and_return(tweets)
15
16 expect(gluttons.recent).to eql(%w[@John @Jane])
17 end
Mutation Testing with mutant
Automated
Probably more clever than you
Mutation Testing with mutant
Example #1: Internal API
1 it 'returns a user when given a valid id' do
2 expect(get(:show, id: 1)).to eq(id: 1, name: 'John')
3 end
4
5 it 'renders JSON error when given an invalid id' do
6 expect(get(:show, id: 0))
7 .to eq(error: "Could not find User with 'id'=0")
8 end
1 class UsersController < ApplicationController
2 def show
3 render json: User.find(params[:id].to_i)
4 rescue User::RecordNotFound => error
5 render json: { error: error.to_s }
6 end
7 end
1 def show
2 - render json: User.find(params[:id].to_i)
3 + render json: User.find(Integer(params[:id]))
4 rescue User::RecordNotFound => error
5 render json: { error: error.to_s }
6 end
1 def show
2 - render json: User.find(params[:id].to_i)
3 + render json: User.find(params.fetch(:id).to_i)
4 rescue User::RecordNotFound => error
5 render json: { error: error.to_s }
6 end
1 def show
2 - render json: User.find(params[:id].to_i)
3 + render json: User.find(Integer(params.fetch(:id)))
4 rescue User::RecordNotFound => error
5 render json: { error: error.to_s }
6 end
1 class UsersController < ApplicationController
2 def created_after
3 after = Date.parse(params[:after])
4 render json: User.recent(after)
5 end
6 end
1 def created_after
2 - after = Date.parse(params[:after])
3 + after = Date.iso8601(params[:after])
4 render json: User.recent(after)
5 end
1 def created_after
2 - after = Date.parse(params[:after])
3 + after = Date.iso8601(params[:after])
4 render json: User.recent(after)
5 end
1 def created_after
2 - after = Date.parse(params[:after])
3 + after = Date.iso8601(params[:after])
4 render json: User.recent(after)
5 end
“2017-05-01"
"H29.05.01"
"Tue May 01 00:00:00 2017"
"Tue, 01 May 2017 00:00:00 +0000"
"Tue, 01 May 2017 00:00:00 GMT"
"May"
"I may be complete garbage"
“2017-05-01"
Date.parseDate.iso8601
Example #2: Hardening Regular Expressions
1 usernames.select do |username|
2 username =~ /^(John|Alain).+$/
3 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username =~ /A(John|Alain).+$/
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username =~ /^(John|Alain).+z/
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username =~ /^(Alain).+$/
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username =~ /^(John).+$/
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username =~ /^(?:John|Alain).+$/
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username.match?(/^(John|Alain).+$/)
4 end
1 usernames.select do |username|
2 - username =~ /^(John|Alain).+$/
3 + username.match?(/A(?:John|Alain).+z/)
4 end
Example #3: Learning about your HTTP Client
1 def stars_for(repo)
2 url = "https://api.github.com/repos/#{repo}"
3 data = HTTParty.get(url).to_h
4
5 data['stargazers_count']
6 end
1 def stars_for(repo)
2 url = "https://api.github.com/repos/#{repo}"
3 - data = HTTParty.get(url).to_h
4 + data = HTTParty.get(url)
5
6 data['stargazers_count']
7 end
Practicality
/^(John|Alain).+$/
/A(John|Alain).+$/
/^(John|Alain).+z/
/^(Alain).+$/
/^(John).+$/
/^(?:John|Alain).+$/
$ mutant --use rspec --since master
$ mutant 
--use rspec 
--since master 
‘YourApp::User’
1 module YourApp
2 class User < ActiveRecord::Base
3 # Dozens of includes, scopes, class methods, rails magic
4 # 100+ methods
5
6 def validate_email
7 # Simple method you're fixing
8 end
9 end
10 end
1 RSpec.describe YourApp::User do
2 # 100s of tests and setup unrelated to your task
3
4 describe '#validate_email' do
5 # Half dozen tests you are focusing on
6 end
7 end
mutant - Your Secret Weapon
Thanks!
John Backus - @backus - john@blockscore.com

More Related Content

What's hot

What's hot (7)

Spock
SpockSpock
Spock
 
Nitika3
Nitika3Nitika3
Nitika3
 
Codes
CodesCodes
Codes
 
React Spotlight 2018
React Spotlight 2018React Spotlight 2018
React Spotlight 2018
 
Q
QQ
Q
 
Crossing the streams viktor gamov
Crossing the streams viktor gamovCrossing the streams viktor gamov
Crossing the streams viktor gamov
 
Lenguaje de programación jn
Lenguaje de programación jnLenguaje de programación jn
Lenguaje de programación jn
 

Viewers also liked

How to construct a paragraph
How to construct a paragraphHow to construct a paragraph
How to construct a paragraphMartin McMorrow
 
Tranh lá rụng
Tranh lá rụngTranh lá rụng
Tranh lá rụngDam Nguyen
 
Heart BD2K - mHealth
Heart BD2K - mHealthHeart BD2K - mHealth
Heart BD2K - mHealthBrian Bot
 
Jogg.se, Webbhusets Magentodag
Jogg.se,  Webbhusets MagentodagJogg.se,  Webbhusets Magentodag
Jogg.se, Webbhusets MagentodagPetter Isaksson
 
How to write an introductory paragraph
How to write an introductory paragraphHow to write an introductory paragraph
How to write an introductory paragraphEsther Risco
 
Shell Global
Shell Global Shell Global
Shell Global poortkai
 
The Not-So-General Quiz by Rohit and Parth (Prelims)
The Not-So-General Quiz by Rohit and Parth (Prelims)The Not-So-General Quiz by Rohit and Parth (Prelims)
The Not-So-General Quiz by Rohit and Parth (Prelims)Quiz Club IIT Kanpur
 
Act4 Faith
Act4 FaithAct4 Faith
Act4 Faithjamie25
 

Viewers also liked (11)

How to construct a paragraph
How to construct a paragraphHow to construct a paragraph
How to construct a paragraph
 
Ilfuturomelocostruiscoio
IlfuturomelocostruiscoioIlfuturomelocostruiscoio
Ilfuturomelocostruiscoio
 
Olimpia Valencia López
Olimpia Valencia LópezOlimpia Valencia López
Olimpia Valencia López
 
Tranh lá rụng
Tranh lá rụngTranh lá rụng
Tranh lá rụng
 
Pd thn 2 bhgn tubuh badan
Pd thn 2  bhgn tubuh badanPd thn 2  bhgn tubuh badan
Pd thn 2 bhgn tubuh badan
 
Heart BD2K - mHealth
Heart BD2K - mHealthHeart BD2K - mHealth
Heart BD2K - mHealth
 
Jogg.se, Webbhusets Magentodag
Jogg.se,  Webbhusets MagentodagJogg.se,  Webbhusets Magentodag
Jogg.se, Webbhusets Magentodag
 
How to write an introductory paragraph
How to write an introductory paragraphHow to write an introductory paragraph
How to write an introductory paragraph
 
Shell Global
Shell Global Shell Global
Shell Global
 
The Not-So-General Quiz by Rohit and Parth (Prelims)
The Not-So-General Quiz by Rohit and Parth (Prelims)The Not-So-General Quiz by Rohit and Parth (Prelims)
The Not-So-General Quiz by Rohit and Parth (Prelims)
 
Act4 Faith
Act4 FaithAct4 Faith
Act4 Faith
 

Similar to How to Write Better Code with Mutation Testing

Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестированияMitinPavel
 
java 8 Hands on Workshop
java 8 Hands on Workshopjava 8 Hands on Workshop
java 8 Hands on WorkshopJeanne Boyarsky
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School ProgrammersSiva Arunachalam
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosEdgar Suarez
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”apostlion
 
What's new in Ansible 2.0
What's new in Ansible 2.0What's new in Ansible 2.0
What's new in Ansible 2.0Allan Denot
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test communityKerry Buckley
 
2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcut2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcutPharo
 
Pythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptxPythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptxVigneshChaturvedi1
 
React Native Evening
React Native EveningReact Native Evening
React Native EveningTroy Miles
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patternsTomasz Kowal
 
Spock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted VinkeSpock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted VinkeTed Vinke
 
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013Anton Bangratz
 
Una Critica a Rails by Luca Guidi
Una Critica a Rails by Luca GuidiUna Critica a Rails by Luca Guidi
Una Critica a Rails by Luca GuidiCodemotion
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionarySoba Arjun
 

Similar to How to Write Better Code with Mutation Testing (20)

Антипаттерны модульного тестирования
Антипаттерны модульного тестированияАнтипаттерны модульного тестирования
Антипаттерны модульного тестирования
 
java 8 Hands on Workshop
java 8 Hands on Workshopjava 8 Hands on Workshop
java 8 Hands on Workshop
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutos
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
 
Python slide
Python slidePython slide
Python slide
 
What's new in Ansible 2.0
What's new in Ansible 2.0What's new in Ansible 2.0
What's new in Ansible 2.0
 
Tdd for BT E2E test community
Tdd for BT E2E test communityTdd for BT E2E test community
Tdd for BT E2E test community
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
 
2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcut2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcut
 
Pythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptxPythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptx
 
Why Our Code Smells
Why Our Code SmellsWhy Our Code Smells
Why Our Code Smells
 
React Native Evening
React Native EveningReact Native Evening
React Native Evening
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
Spock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted VinkeSpock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted Vinke
 
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013
Talk about Testing at vienna.rb meetup #2 on Apr 12th, 2013
 
Una Critica a Rails by Luca Guidi
Una Critica a Rails by Luca GuidiUna Critica a Rails by Luca Guidi
Una Critica a Rails by Luca Guidi
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, Dictionary
 

Recently uploaded

5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
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
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 
(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
 
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
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 

Recently uploaded (20)

5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
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
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
(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...
 
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...
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 

How to Write Better Code with Mutation Testing

  • 1. How to Write Better Code with Mutation Testing John Backus - @backus - john@blockscore.com
  • 4. Talk Outline Introduction Improving coverage Learning about Ruby and the code you rely on
  • 5. Line Coverage Lines of Code Run by Tests Total Lines of Code÷
  • 6. Mutation Coverage How much of your code can I change without breaking your tests?
  • 8. 1 class Gluttons 2 def initialize(twitter_client) 3 @twitter = twitter_client 4 end 5 6 def recent 7 query = @twitter.search('"I really enjoy #pizza"') 8 9 query.first(2).map { |tweet| "@#{tweet.author}" } 10 end 11 end 1 RSpec.describe Gluttons do 2 it 'lists the two most recent gluttonous tweeters' do 3 tweets = [double(author: 'John'), double(author: 'Jane')] 4 gluttons = Gluttons.new(double(search: tweets)) 5 6 expect(gluttons.recent).to eql(%w[@John @Jane]) 7 end 8 end
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26. 1 class Gluttons 2 def recent 3 - query = @twitter.search('"I really enjoy #pizza"') 4 + query = @twitter.search('"I really enjoy #hotdogs"') 1 example, 0 failures
  • 27. 1 class Gluttons 2 def recent 3 - query = @twitter.search('"I really enjoy #pizza"') 4 + query = @twitter.search('') 1 example, 0 failures
  • 28. 1 class Gluttons 2 def recent 3 - query = @twitter.search('"I really enjoy #pizza"') 4 + query = @twitter.search 1 example, 0 failures
  • 29. 1 class Gluttons 2 def recent 3 - query.first(2).map { |tweet| "@#{tweet.author}" } 4 + query.first(1).map { |tweet| "@#{tweet.author}" } Failure expected: ["@John", "@Jane"] got: ["@John"]
  • 30. 1 - query.first(2).map { |tweet| "@#{tweet.author}" } 2 + query.first(3).map { |tweet| "@#{tweet.author}" } 3 end 1 example, 0 failures
  • 32. Manual Mutation Testing Hard to outsmart yourself
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44. 1 def recent 2 - query = @twitter.search('"I really enjoy #pizza"') 3 + query = @twitter.search
  • 45. 1 def recent 2 - query = @twitter.search('"I really enjoy #pizza"') 3 + query = @twitter.search(nil)
  • 46. 1 - query.first(2).map { |tweet| "@#{tweet.author}" } 2 + query.last(2).map { |tweet| "@#{tweet.author}" } 3 end
  • 47. 1 - query.first(2).map { |tweet| "@#{tweet.author}" } 2 + query.map { |tweet| "@#{tweet.author}" } 3 end
  • 48. 1 it 'lists the two most recent gluttonous tweeters' do 2 tweets = [ 3 double(author: 'John'), 4 double(author: 'Jane'), 5 double(author: 'Devon') 6 ] 7 8 client = double('Client') 9 gluttons = Gluttons.new(client) 10 11 allow(client) 12 .to receive(:search) 13 .with('"I really enjoy #pizza"') 14 .and_return(tweets) 15 16 expect(gluttons.recent).to eql(%w[@John @Jane]) 17 end
  • 49. Mutation Testing with mutant Automated
  • 50. Probably more clever than you Mutation Testing with mutant
  • 52. 1 it 'returns a user when given a valid id' do 2 expect(get(:show, id: 1)).to eq(id: 1, name: 'John') 3 end 4 5 it 'renders JSON error when given an invalid id' do 6 expect(get(:show, id: 0)) 7 .to eq(error: "Could not find User with 'id'=0") 8 end 1 class UsersController < ApplicationController 2 def show 3 render json: User.find(params[:id].to_i) 4 rescue User::RecordNotFound => error 5 render json: { error: error.to_s } 6 end 7 end
  • 53. 1 def show 2 - render json: User.find(params[:id].to_i) 3 + render json: User.find(Integer(params[:id])) 4 rescue User::RecordNotFound => error 5 render json: { error: error.to_s } 6 end
  • 54. 1 def show 2 - render json: User.find(params[:id].to_i) 3 + render json: User.find(params.fetch(:id).to_i) 4 rescue User::RecordNotFound => error 5 render json: { error: error.to_s } 6 end
  • 55. 1 def show 2 - render json: User.find(params[:id].to_i) 3 + render json: User.find(Integer(params.fetch(:id))) 4 rescue User::RecordNotFound => error 5 render json: { error: error.to_s } 6 end
  • 56. 1 class UsersController < ApplicationController 2 def created_after 3 after = Date.parse(params[:after]) 4 render json: User.recent(after) 5 end 6 end
  • 57. 1 def created_after 2 - after = Date.parse(params[:after]) 3 + after = Date.iso8601(params[:after]) 4 render json: User.recent(after) 5 end
  • 58. 1 def created_after 2 - after = Date.parse(params[:after]) 3 + after = Date.iso8601(params[:after]) 4 render json: User.recent(after) 5 end
  • 59. 1 def created_after 2 - after = Date.parse(params[:after]) 3 + after = Date.iso8601(params[:after]) 4 render json: User.recent(after) 5 end “2017-05-01" "H29.05.01" "Tue May 01 00:00:00 2017" "Tue, 01 May 2017 00:00:00 +0000" "Tue, 01 May 2017 00:00:00 GMT" "May" "I may be complete garbage" “2017-05-01" Date.parseDate.iso8601
  • 60. Example #2: Hardening Regular Expressions
  • 61. 1 usernames.select do |username| 2 username =~ /^(John|Alain).+$/ 3 end
  • 62. 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username =~ /A(John|Alain).+$/ 4 end 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username =~ /^(John|Alain).+z/ 4 end
  • 63. 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username =~ /^(Alain).+$/ 4 end 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username =~ /^(John).+$/ 4 end
  • 64. 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username =~ /^(?:John|Alain).+$/ 4 end
  • 65. 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username.match?(/^(John|Alain).+$/) 4 end
  • 66. 1 usernames.select do |username| 2 - username =~ /^(John|Alain).+$/ 3 + username.match?(/A(?:John|Alain).+z/) 4 end
  • 67. Example #3: Learning about your HTTP Client
  • 68. 1 def stars_for(repo) 2 url = "https://api.github.com/repos/#{repo}" 3 data = HTTParty.get(url).to_h 4 5 data['stargazers_count'] 6 end
  • 69. 1 def stars_for(repo) 2 url = "https://api.github.com/repos/#{repo}" 3 - data = HTTParty.get(url).to_h 4 + data = HTTParty.get(url) 5 6 data['stargazers_count'] 7 end
  • 72. $ mutant --use rspec --since master
  • 73. $ mutant --use rspec --since master ‘YourApp::User’
  • 74. 1 module YourApp 2 class User < ActiveRecord::Base 3 # Dozens of includes, scopes, class methods, rails magic 4 # 100+ methods 5 6 def validate_email 7 # Simple method you're fixing 8 end 9 end 10 end
  • 75. 1 RSpec.describe YourApp::User do 2 # 100s of tests and setup unrelated to your task 3 4 describe '#validate_email' do 5 # Half dozen tests you are focusing on 6 end 7 end
  • 76. mutant - Your Secret Weapon
  • 77. Thanks! John Backus - @backus - john@blockscore.com