SlideShare a Scribd company logo
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

Spock
SpockSpock
React Spotlight 2018
React Spotlight 2018React Spotlight 2018
React Spotlight 2018
Phong Huynh
 
Crossing the streams viktor gamov
Crossing the streams viktor gamovCrossing the streams viktor gamov
Crossing the streams viktor gamov
confluent
 
Lenguaje de programación jn
Lenguaje de programación jnLenguaje de programación jn
Lenguaje de programación jn
Jhiselys Vásquez
 

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 paragraph
Martin McMorrow
 
Ilfuturomelocostruiscoio
IlfuturomelocostruiscoioIlfuturomelocostruiscoio
Ilfuturomelocostruiscoio
Nicola Biasiolli
 
Olimpia Valencia López
Olimpia Valencia LópezOlimpia Valencia López
Olimpia Valencia López
Yago López Rodríguez
 
Tranh lá rụng
Tranh lá rụngTranh lá rụng
Tranh lá rụng
Dam Nguyen
 
Pd thn 2 bhgn tubuh badan
Pd thn 2  bhgn tubuh badanPd thn 2  bhgn tubuh badan
Pd thn 2 bhgn tubuh badan
Faizah Mohd Razali
 
Heart BD2K - mHealth
Heart BD2K - mHealthHeart BD2K - mHealth
Heart BD2K - mHealth
Brian Bot
 
Jogg.se, Webbhusets Magentodag
Jogg.se,  Webbhusets MagentodagJogg.se,  Webbhusets Magentodag
Jogg.se, Webbhusets Magentodag
Petter Isaksson
 
How to write an introductory paragraph
How to write an introductory paragraphHow to write an introductory paragraph
How to write an introductory paragraph
Esther 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 Workshop
Jeanne Boyarsky
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
Patrick Huesler
 
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
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
Wes Oldenbeuving
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
apostlion
 
Python slide
Python slidePython 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
Allan 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
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
Leonardo Soto
 
2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcut2013 lecture-02-syntax shortnewcut
2013 lecture-02-syntax shortnewcut
Pharo
 
Pythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptxPythonlearn-03-Conditional.pptx
Pythonlearn-03-Conditional.pptx
VigneshChaturvedi1
 
Why Our Code Smells
Why Our Code SmellsWhy Our Code Smells
Why Our Code Smells
TiNguyn863920
 
React Native Evening
React Native EveningReact Native Evening
React Native Evening
Troy Miles
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
Tomasz 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 Vinke
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
Anton 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 Guidi
Codemotion
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, Dictionary
Soba 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

Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Shahin Sheidaei
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Globus
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Jay Das
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
rickgrimesss22
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
Srikant77
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Globus
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Natan Silnitsky
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Mind IT Systems
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 

Recently uploaded (20)

Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
Gamify Your Mind; The Secret Sauce to Delivering Success, Continuously Improv...
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
 
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptxTop Features to Include in Your Winzo Clone App for Business Growth (4).pptx
Top Features to Include in Your Winzo Clone App for Business Growth (4).pptx
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.ILBeyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
Beyond Event Sourcing - Embracing CRUD for Wix Platform - Java.IL
 
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
Custom Healthcare Software for Managing Chronic Conditions and Remote Patient...
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 

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