SlideShare a Scribd company logo
Three Advanced

DeveloperTestingTechniques
Alistair McKinnell
@amckinnell
How do we 

change code safely?
Advanced Developer Testing
Changing Code
Existing Behaviour New Behaviour
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
Gilded Rose
1 class GildedRose
2 attr_reader :items
3
4 def initialize(items)
5 @items = items
6 end
7
8 def update_quality
9 @items.each do |item|
10 if item.name != 'Aged Brie' and
11 item.name != 'Backstage passes to a TAFKAL80ETC concert'
12 if item.quality > 0
13 if item.name != 'Sulfuras, Hand of Ragnaros'
14 item.quality = item.quality - 1
15 end
16 end
17 else
18 if item.quality < 50
19 item.quality = item.quality + 1
20 if item.name == 'Backstage passes to a TAFKAL80ETC concert'
21 if item.sell_in < 11
22 if item.quality < 50
23 item.quality = item.quality + 1
24 end
25 end
26 if item.sell_in < 6
27 if item.quality < 50
28 item.quality = item.quality + 1
29 end
30 end
31 end
32 end
33 end
34 if item.name != 'Sulfuras, Hand of Ragnaros'
35 item.sell_in = item.sell_in - 1
36 end
37 if item.sell_in < 0
38 if item.name != 'Aged Brie'
39 if item.name != 'Backstage passes to a TAFKAL80ETC concert'
40 if item.quality > 0
41 if item.name != 'Sulfuras, Hand of Ragnaros'
42 item.quality = item.quality - 1
43 end
44 end
45 else
46 item.quality = item.quality - item.quality
47 end
48 else
49 if item.quality < 50
50 item.quality = item.quality + 1
51 end
52 end
53 end
54 end
55 end
56
57 end
!
“Conjured” items degrade 

twice as fast as normal items.
New Behaviour
Existing Behaviour

(Refactored)
New Behaviour

(Conjured Item)
Changing Code
Are we ready to 

change code safely?
Nope
Refactoring safely

requires tests.
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
expected: nil
got: "Mail Armour, 9, 19"
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
expected: nil
got: "Mail Armour, 9, 19"
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new(‘Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
expected: nil
got: "Mail Armour, 8, 18"
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq(nil)
end
end
expected: nil
got: "Mail Armour, 8, 18"
describe GildedRose do
it 'knows how to update quality for items' do
items = [Item.new('Mail Armour', 10, 20)]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new('Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new('Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new(‘Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
expect(subject.items[1].to_s).to eq(nil)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
expect(subject.items[1].to_s).to eq(nil)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new(‘Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
expect(subject.items[1].to_s).to eq(nil)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
expect(subject.items[1].to_s).to eq(nil)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new(‘Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
expect(subject.items[1].to_s).to eq(‘Aged Brie, 3, 10')
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
expect(subject.items[1].to_s).to eq(‘Aged Brie, 2, 11')
end
end
describe GildedRose do
it 'knows how to update quality for items' do
items = [
Item.new('Mail Armour', 10, 20),
Item.new(‘Aged Brie', 4, 9)
]
subject = GildedRose.new(items)
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19')
expect(subject.items[1].to_s).to eq(‘Aged Brie, 3, 10')
subject.update_quality
expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18')
expect(subject.items[1].to_s).to eq(‘Aged Brie, 2, 11')
end
end
Let’s organize our test
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
end
def characterize(subject, days)
end
def expected
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def characterize(subject, days)
characterization = []
(1..days).each do
subject.update_quality
subject.items.each { |item| characterization << item.to_s }
end
characterization
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
[
'Mail Armour, 9, 19',
'Aged Brie, 3, 10',
'Mail Armour, 8, 18',
'Aged Brie, 2, 11'
]
end
Are we ready to 

change code safely?
Nope
Characterization

is incomplete.
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
Advanced Developer Testing
53%
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9]
]
item_attributes.map { |args| Item.new(*args) }
end
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17]
]
item_attributes.map { |args| Item.new(*args) }
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
[
'Mail Armour, 9, 19',
'Aged Brie, 3, 10',
'Backstage passes to a TAFKAL80ETC concert, 14, 18',
'Mail Armour, 8, 18',
'Aged Brie, 2, 11',
'Backstage passes to a TAFKAL80ETC concert, 13, 19',
]
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
[
'Mail Armour, 9, 19',
'Aged Brie, 3, 10',
'Backstage passes to a TAFKAL80ETC concert, 14, 18',
'Mail Armour, 8, 18',
'Aged Brie, 2, 11',
'Backstage passes to a TAFKAL80ETC concert, 13, 19',
]
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
60%
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
if item.name == 'Backstage passes to a TAFKAL80ETC concert'
if item.sell_in < 11
if item.quality < 50
item.quality = item.quality + 1
end
end
if item.sell_in < 6
if item.quality < 50
item.quality = item.quality + 1
end
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
This is what 

we want to do
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
def expected
[
'Mail Armour, 9, 19',
'Aged Brie, 3, 10',
'Backstage passes to a TAFKAL80ETC concert, 14, 18',
'Mail Armour, 8, 18',
'Aged Brie, 2, 11',
'Backstage passes to a TAFKAL80ETC concert, 13, 19’,
and many more expected results
]
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def characterize(subject, days)
characterization = []
(1..days).each do
subject.update_quality
characterization.concat(subject.items.map(&:to_s))
end
Digest::SHA2.hexdigest(characterization.join)
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def characterize(subject, days)
characterization = []
(1..days).each do
subject.update_quality
characterization.concat(subject.items.map(&:to_s))
end
Digest::SHA2.hexdigest(characterization.join)
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
[
'Mail Armour, 9, 19',
'Aged Brie, 3, 10',
'Backstage passes to a TAFKAL80ETC concert, 14, 18',
'Mail Armour, 8, 18',
'Aged Brie, 2, 11',
'Backstage passes to a TAFKAL80ETC concert, 13, 19’,
]
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
nil
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
nil
end
expected: nil
got: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5”
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
nil
end
expected: nil
got: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5”
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def expected
‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
def expected
‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
expected: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5”
got: “fb61e7fdfffcba653fec … 9ae0512470a974b1561e"
def expected
‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
def expected
‘fb61e7fdfffcba653fec … 9ae0512470a974b1561e’
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
100%
Are we ready to 

change code safely?
Nope
Characterization

is incomplete.
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
class GildedRose
attr_reader :items
def initialize(items)
@items = items
end
def update_quality
@items.each do |item|
…
if item.name != 'Sulfuras, Hand of Ragnaros'
item.sell_in = item.sell_in - 1
end
…
end
end
end
class GildedRose
attr_reader :items
def initialize(items)
@items = items
end
def update_quality
@items.each do |item|
…
# if item.name != 'Sulfuras, Hand of Ragnaros'
item.sell_in = item.sell_in - 1
# end
…
end
end
end
class GildedRose
attr_reader :items
def initialize(items)
@items = items
end
def update_quality
@items.each do |item|
…
# if item.name != 'Sulfuras, Hand of Ragnaros'
item.sell_in = item.sell_in - 1
# end
…
end
end
end
Comment out 

two lines
Test still passes?
class GildedRose
attr_reader :items
def initialize(items)
@items = items
end
def update_quality
@items.each do |item|
…
# if item.name != 'Sulfuras, Hand of Ragnaros'
item.sell_in = item.sell_in - 1
# end
…
end
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
Are we ready to 

change code safely?
Nope
Characterization

is incomplete.
github.com/mbj/mutant
Mutant configuration:
Subjects: 2

Mutations: 476
Kills: 454
Alive: 22
Coverage: 95.38%
Expected: 100.00%
- if (item.quality > 0)
+ if (item.quality > 1)
- if (item.quality < 50)
+ if (item.quality < 49)
- if (item.quality < 50)
+ if (item.quality < 51)
- if (item.quality < 50)
+ if true
- if (item.quality < 50)
+ if 50
- if (item.name == "Backstage passes to a TAFKAL80ETC concert")
+ if item.name.eql?("Backstage passes to a TAFKAL80ETC concert")
def items
item_attributes = [
['Mail Armour', 10, 20],
['Aged Brie', 4, 9],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
Subjects: 2
Mutations: 476
Kills: 454
Alive: 22
Coverage: 95.38%
Expected: 100.00%
Before After
Subjects: 2
Mutations: 476
Kills: 474
Alive: 4
Coverage: 99.16%
Expected: 100.00%
Are we ready to 

change code safely?
Yep
New BehaviourExisting Behaviour
Changing Code
Advanced Developer Testing
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
Refactoring
1 class GildedRose
2 attr_reader :items
3
4 def initialize(items)
5 @items = items
6 end
7
8 def update_quality
9 @items.each { |item| update_item_quality(item) }
10 end
11
12 private
13
14 def update_item_quality(item)
15 return if item.name == 'Sulfuras, Hand of Ragnaros'
16
17 perform_inventory_rollover(item)
18 perform_inventory_expiration(item)
19 end
20
21 def perform_inventory_rollover(item)
22 item.sell_in -= 1
23
24 case item.name
25 when 'Aged Brie'
26 increase_quality(item)
27 when 'Backstage passes to a TAFKAL80ETC concert'
28 increase_quality(item)
29 increase_quality(item) if item.sell_in < 10
30 increase_quality(item) if item.sell_in < 5
31 else
32 decrease_quality(item)
33 end
34 end
35
36 def perform_inventory_expiration(item)
37 return unless expired?(item)
38
39 case item.name
40 when 'Aged Brie'
41 increase_quality(item)
42 when 'Backstage passes to a TAFKAL80ETC concert'
43 writeoff(item)
44 else
45 decrease_quality(item)
46 end
47 end
48
49 def expired?(item)
50 item.sell_in < 0
51 end
52
53 def decrease_quality(item)
54 item.quality -= 1 if 0 < item.quality
55 end
56
57 def increase_quality(item)
58 item.quality += 1 if item.quality < 50
59 end
60
61 def writeoff(item)
62 item.quality = 0
63 end
64
65 end
“Conjured” items degrade 

twice as fast as normal items.
New Behaviour
def perform_inventory_rollover(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_expiration(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_rollover(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_expiration(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80],
[‘Conjured Mana', 13, 50]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80],
[‘Conjured Mana', 13, 50]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
def expected
‘1768fa473f323772588a … 13eab4018717ea78ea0c’
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 20)
expect(characterization).to eq(expected)
end
end
expected: “1768fa473f323772588a … 13eab4018717ea78ea0c”
got: “6cf1111d5865232381f1 … 9d00ff8e831395de5420"
def expected
‘1768fa473f323772588a … 13eab4018717ea78ea0c’
end
New BehaviourExisting Behaviour
Changing Code
Are we ready to 

change code safely?
Nope
Can’t distinguish existing
and new behaviour.
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
Whatever the code does.
Existing Behaviour
“Conjured” items degrade

twice as fast as normal items.
New Behaviour
github.com/kytrinyx/approvals
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
def characterize(subject, days)
characterization = []
(1..days).each_with_index do |day|
subject.update_quality
characterization << "Day #{day} of #{days}"
subject.items.each { |item| characterization <<
" #{item.to_s}" }
end
characterization.join("n")
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
def characterize(subject, days)
characterization = []
(1..days).each_with_index do |day|
subject.update_quality
characterization << "Day #{day} of #{days}"
subject.items.each { |item| characterization <<
" #{item.to_s}" }
end
characterization.join("n")
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
def characterize(subject, days)
characterization = []
(1..days).each_with_index do |day|
subject.update_quality
characterization << "Day #{day} of #{days}"
subject.items.each { |item| characterization <<
" #{item.to_s}" }
end
characterization.join("n")
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
Approvals::ApprovalError: Approval Error: Approval file 

“spec/fixtures/approvals/gildedrose/ 

knows_how_to_update_quality_for_items.approved.txt"

not found.
knows_how_to_update_quality_for_items.received.txt
1 Day 1 of 20
2 Mail Armour, 9, 19
3 Mail Armour, 9, 0
4 Aged Brie, 3, 10
5 Aged Brie, 0, 50
6 Backstage passes to a TAFKAL80ETC concert, 14, 18
7 Backstage passes to a TAFKAL80ETC concert, 4, 50
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Day 2 of 20
10 Mail Armour, 8, 18
…
153 Day 20 of 20
154 Mail Armour, -10, 0
155 Mail Armour, -10, 0
156 Aged Brie, -16, 45
157 Aged Brie, -19, 50
158 Backstage passes to a TAFKAL80ETC concert, -5, 0
159 Backstage passes to a TAFKAL80ETC concert, -15, 0
160 Sulfuras, Hand of Ragnaros, -1, 80
knows_how_to_update_quality_for_items.approved.txt
1 Day 1 of 20
2 Mail Armour, 9, 19
3 Mail Armour, 9, 0
4 Aged Brie, 3, 10
5 Aged Brie, 0, 50
6 Backstage passes to a TAFKAL80ETC concert, 14, 18
7 Backstage passes to a TAFKAL80ETC concert, 4, 50
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Day 2 of 20
10 Mail Armour, 8, 18
…
153 Day 20 of 20
154 Mail Armour, -10, 0
155 Mail Armour, -10, 0
156 Aged Brie, -16, 45
157 Aged Brie, -19, 50
158 Backstage passes to a TAFKAL80ETC concert, -5, 0
159 Backstage passes to a TAFKAL80ETC concert, -15, 0
160 Sulfuras, Hand of Ragnaros, -1, 80
knows_how_to_update_quality_for_items.approved.txt
1 Day 1 of 20
2 Mail Armour, 9, 19
3 Mail Armour, 9, 0
4 Aged Brie, 3, 10
5 Aged Brie, 0, 50
6 Backstage passes to a TAFKAL80ETC concert, 14, 18
7 Backstage passes to a TAFKAL80ETC concert, 4, 50
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Day 2 of 20
10 Mail Armour, 8, 18
…
153 Day 20 of 20
154 Mail Armour, -10, 0
155 Mail Armour, -10, 0
156 Aged Brie, -16, 45
157 Aged Brie, -19, 50
158 Backstage passes to a TAFKAL80ETC concert, -5, 0
159 Backstage passes to a TAFKAL80ETC concert, -15, 0
160 Sulfuras, Hand of Ragnaros, -1, 80
New BehaviourExisting Behaviour
Changing Code
def perform_inventory_rollover(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_expiration(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_rollover(item
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def perform_inventory_expiration(item)
case item.name
when 'Conjured Mana'
decrease_quality(item)
decrease_quality(item)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80],
[‘Conjured Mana', 13, 50]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
def items
item_attributes = [
['Mail Armour', 10, 20],
['Mail Armour', 10, 1],
['Aged Brie', 4, 9],
['Aged Brie', 1, 49],
['Backstage passes to a TAFKAL80ETC concert', 15, 17],
['Backstage passes to a TAFKAL80ETC concert', 5, 49],
['Sulfuras, Hand of Ragnaros', -1, 80],
[‘Conjured Mana', 13, 50]
]
item_attributes.map { |args| Item.new(*args) }
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
characterization = characterize(subject, 2)
expect(characterization).to eq(expected)
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
describe GildedRose do
it 'knows how to update quality for items' do
subject = GildedRose.new(items)
verify { characterize(subject, 20) }
end
end
Approvals::ApprovalError: Approval Error: Received file
“spec/fixtures/approvals/gildedrose/
knows_how_to_update_quality_for_items.received.txt”
does not match approved
“spec/fixtures/approvals/gildedrose/
knows_how_to_update_quality_for_items.approved.txt".
knows_how_to_update_quality_for_items.received.txt
4 Aged Brie, 3, 10
5 Aged Brie, 0, 50
6 Backstage passes to a TAFKAL80ETC concert, 14, 18
7 Backstage passes to a TAFKAL80ETC concert, 4, 50
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Conjured Mana, 12, 48
10 Day 2 of 20
11 Mail Armour, 8, 18
12 …
knows_how_to_update_quality_for_items.approved.txt
4 Aged Brie, 3, 10
5 Aged Brie, 0, 50
6 Backstage passes to a TAFKAL80ETC concert, 14, 18
7 Backstage passes to a TAFKAL80ETC concert, 4, 50
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Day 2 of 20
10 Mail Armour, 8, 18
11 …
knows_how_to_update_quality_for_items.received.txt
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Conjured Mana, 12, 48
10 Day 2 of 20
11 Mail Armour, 8, 18
12 Mail Armour, 8, 0
13 Aged Brie, 2, 11
14 Aged Brie, -1, 50
15 Backstage passes to a TAFKAL80ETC concert, 13, 19
16 Backstage passes to a TAFKAL80ETC concert, 3, 50
17 Sulfuras, Hand of Ragnaros, -1, 80
18 Conjured Mana, 11, 46
19 Day 3 of 20
20 Mail Armour, 7, 17
21 Mail Armour, 7, 0
22 Aged Brie, 1, 12
23 Aged Brie, -2, 50
24 Backstage passes to a TAFKAL80ETC concert, 12, 20
25 Backstage passes to a TAFKAL80ETC concert, 2, 50
26 Sulfuras, Hand of Ragnaros, -1, 80
27 Conjured Mana, 10, 44
28 Day 4 of 20
29 Mail Armour, 6, 16
30 …
knows_how_to_update_quality_for_items.approved.txt
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Conjured Mana, 12, 48
10 Day 2 of 20
11 Mail Armour, 8, 18
12 Mail Armour, 8, 0
13 Aged Brie, 2, 11
14 Aged Brie, -1, 50
15 Backstage passes to a TAFKAL80ETC concert, 13, 19
16 Backstage passes to a TAFKAL80ETC concert, 3, 50
17 Sulfuras, Hand of Ragnaros, -1, 80
18 Conjured Mana, 11, 46
19 Day 3 of 20
20 Mail Armour, 7, 17
21 Mail Armour, 7, 0
22 Aged Brie, 1, 12
23 Aged Brie, -2, 50
24 Backstage passes to a TAFKAL80ETC concert, 12, 20
25 Backstage passes to a TAFKAL80ETC concert, 2, 50
26 Sulfuras, Hand of Ragnaros, -1, 80
27 Conjured Mana, 10, 44
28 Day 4 of 20
29 Mail Armour, 6, 16
30 …
knows_how_to_update_quality_for_items.approved.txt
8 Sulfuras, Hand of Ragnaros, -1, 80
9 Conjured Mana, 12, 48
10 Day 2 of 20
11 Mail Armour, 8, 18
12 Mail Armour, 8, 0
13 Aged Brie, 2, 11
14 Aged Brie, -1, 50
15 Backstage passes to a TAFKAL80ETC concert, 13, 19
16 Backstage passes to a TAFKAL80ETC concert, 3, 50
17 Sulfuras, Hand of Ragnaros, -1, 80
18 Conjured Mana, 11, 46
19 Day 3 of 20
20 Mail Armour, 7, 17
21 Mail Armour, 7, 0
22 Aged Brie, 1, 12
23 Aged Brie, -2, 50
24 Backstage passes to a TAFKAL80ETC concert, 12, 20
25 Backstage passes to a TAFKAL80ETC concert, 2, 50
26 Sulfuras, Hand of Ragnaros, -1, 80
27 Conjured Mana, 10, 44
28 Day 4 of 20
29 Mail Armour, 6, 16
30 …
We win.
We preserved

existing behaviour and
added new behaviour.
Characterization
Testing
Approval
Testing
Code
Coverage
Mutation
Testing
Are we ready to 

change code safely?
Changing Code
Existing Behaviour New Behaviour
Changing Code
New Behaviour

(ApprovalTests)
Existing Behaviour

(CharacterizationTests)
Be amazing at

changing code safely.
github.com/amckinnell/developer-testing
Recommended Reading

More Related Content

PDF
Two Trains and Other Refactoring Analogies
PDF
RSpock Testing Framework for Ruby
PDF
ActiveRecord Query Interface (2), Season 2
PPTX
Refactoring domain driven design way
PDF
What Can Journalists Teach Developers About Writing Source Code?
KEY
Agile Tour Shanghai December 2011
PDF
Simple Design
PDF
The Boy Scout Rule
Two Trains and Other Refactoring Analogies
RSpock Testing Framework for Ruby
ActiveRecord Query Interface (2), Season 2
Refactoring domain driven design way
What Can Journalists Teach Developers About Writing Source Code?
Agile Tour Shanghai December 2011
Simple Design
The Boy Scout Rule

Similar to Advanced Developer Testing (20)

PDF
Tale of the Gilded Rose
PDF
Testing Ruby with Rspec (a beginner's guide)
KEY
Refactor like a boss
KEY
あたかも自然言語を書くようにコーディングしてみる
PDF
Rails workshop for Java people (September 2015)
PDF
ScotRuby - Dark side of ruby
PDF
R spec let there be tests
KEY
Intro to Ruby - Twin Cities Code Camp 7
KEY
Introduction to Ruby
PDF
RedDot Ruby Conf 2014 - Dark side of ruby
PDF
All Objects are created .equal?
PDF
RSpec best practice - avoid using before and let
KEY
Ruby objects
PPT
fixtures_vs_AR_vs_factories.ppt
KEY
An introduction to Ruby
PDF
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
PDF
Dnipro conf
PDF
Code Refactoring - Live Coding Demo (JavaDay 2014)
PPTX
Cuke2Beer
PDF
Story for a Ruby on Rails Single Engineer
Tale of the Gilded Rose
Testing Ruby with Rspec (a beginner's guide)
Refactor like a boss
あたかも自然言語を書くようにコーディングしてみる
Rails workshop for Java people (September 2015)
ScotRuby - Dark side of ruby
R spec let there be tests
Intro to Ruby - Twin Cities Code Camp 7
Introduction to Ruby
RedDot Ruby Conf 2014 - Dark side of ruby
All Objects are created .equal?
RSpec best practice - avoid using before and let
Ruby objects
fixtures_vs_AR_vs_factories.ppt
An introduction to Ruby
The Trailblazer Ride from the If Jungle into a Civilised Railway Station - Or...
Dnipro conf
Code Refactoring - Live Coding Demo (JavaDay 2014)
Cuke2Beer
Story for a Ruby on Rails Single Engineer
Ad

More from Alistair McKinnell (10)

PDF
Succeeding with Specification by Example
PDF
Don't Settle for Poor Names (Or Poor Design)
PDF
Don't Settle for Poor Names
PDF
Ubiquitous Testing
KEY
Commonality and Variability Analysis: Avoiding Duplicate Code
KEY
Pair Programming
KEY
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
PPT
The Story of a Story
PPT
The Testing Landscape
PPT
Struggling to Create Maintainable Unit Tests?
Succeeding with Specification by Example
Don't Settle for Poor Names (Or Poor Design)
Don't Settle for Poor Names
Ubiquitous Testing
Commonality and Variability Analysis: Avoiding Duplicate Code
Pair Programming
Agile Transition in Trouble? Using the Kotter Change Model as a Diagnostic Tool
The Story of a Story
The Testing Landscape
Struggling to Create Maintainable Unit Tests?
Ad

Recently uploaded (20)

PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Understanding Forklifts - TECH EHS Solution
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
ai tools demonstartion for schools and inter college
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
medical staffing services at VALiNTRY
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
Nekopoi APK 2025 free lastest update
PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
L1 - Introduction to python Backend.pptx
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
history of c programming in notes for students .pptx
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
Design an Analysis of Algorithms I-SECS-1021-03
Understanding Forklifts - TECH EHS Solution
Reimagine Home Health with the Power of Agentic AI​
ai tools demonstartion for schools and inter college
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Which alternative to Crystal Reports is best for small or large businesses.pdf
medical staffing services at VALiNTRY
Odoo Companies in India – Driving Business Transformation.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Nekopoi APK 2025 free lastest update
PTS Company Brochure 2025 (1).pdf.......
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
L1 - Introduction to python Backend.pptx
Navsoft: AI-Powered Business Solutions & Custom Software Development
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
history of c programming in notes for students .pptx
How Creative Agencies Leverage Project Management Software.pdf
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Wondershare Filmora 15 Crack With Activation Key [2025

Advanced Developer Testing

  • 2. How do we 
 change code safely?
  • 7. 1 class GildedRose 2 attr_reader :items 3 4 def initialize(items) 5 @items = items 6 end 7 8 def update_quality 9 @items.each do |item| 10 if item.name != 'Aged Brie' and 11 item.name != 'Backstage passes to a TAFKAL80ETC concert' 12 if item.quality > 0 13 if item.name != 'Sulfuras, Hand of Ragnaros' 14 item.quality = item.quality - 1 15 end 16 end 17 else 18 if item.quality < 50 19 item.quality = item.quality + 1 20 if item.name == 'Backstage passes to a TAFKAL80ETC concert' 21 if item.sell_in < 11 22 if item.quality < 50 23 item.quality = item.quality + 1 24 end 25 end 26 if item.sell_in < 6 27 if item.quality < 50 28 item.quality = item.quality + 1 29 end 30 end 31 end 32 end 33 end 34 if item.name != 'Sulfuras, Hand of Ragnaros' 35 item.sell_in = item.sell_in - 1 36 end 37 if item.sell_in < 0 38 if item.name != 'Aged Brie' 39 if item.name != 'Backstage passes to a TAFKAL80ETC concert' 40 if item.quality > 0 41 if item.name != 'Sulfuras, Hand of Ragnaros' 42 item.quality = item.quality - 1 43 end 44 end 45 else 46 item.quality = item.quality - item.quality 47 end 48 else 49 if item.quality < 50 50 item.quality = item.quality + 1 51 end 52 end 53 end 54 end 55 end 56 57 end !
  • 8. “Conjured” items degrade 
 twice as fast as normal items. New Behaviour
  • 10. Are we ready to 
 change code safely?
  • 13. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end
  • 14. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end expected: nil got: "Mail Armour, 9, 19"
  • 15. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end expected: nil got: "Mail Armour, 9, 19"
  • 16. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') end end
  • 17. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new(‘Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end
  • 18. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end expected: nil got: "Mail Armour, 8, 18"
  • 19. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq(nil) end end expected: nil got: "Mail Armour, 8, 18"
  • 20. describe GildedRose do it 'knows how to update quality for items' do items = [Item.new('Mail Armour', 10, 20)] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') end end
  • 21. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new('Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') end end
  • 22. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new('Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') end end
  • 23. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new(‘Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') expect(subject.items[1].to_s).to eq(nil) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') expect(subject.items[1].to_s).to eq(nil) end end
  • 24. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new(‘Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') expect(subject.items[1].to_s).to eq(nil) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') expect(subject.items[1].to_s).to eq(nil) end end
  • 25. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new(‘Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') expect(subject.items[1].to_s).to eq(‘Aged Brie, 3, 10') subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') expect(subject.items[1].to_s).to eq(‘Aged Brie, 2, 11') end end
  • 26. describe GildedRose do it 'knows how to update quality for items' do items = [ Item.new('Mail Armour', 10, 20), Item.new(‘Aged Brie', 4, 9) ] subject = GildedRose.new(items) subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 9, 19') expect(subject.items[1].to_s).to eq(‘Aged Brie, 3, 10') subject.update_quality expect(subject.items[0].to_s).to eq('Mail Armour, 8, 18') expect(subject.items[1].to_s).to eq(‘Aged Brie, 2, 11') end end Let’s organize our test
  • 27. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 28. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def items end def characterize(subject, days) end def expected end
  • 29. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9] ] item_attributes.map { |args| Item.new(*args) } end
  • 30. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def characterize(subject, days) characterization = [] (1..days).each do subject.update_quality subject.items.each { |item| characterization << item.to_s } end characterization end
  • 31. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected [ 'Mail Armour, 9, 19', 'Aged Brie, 3, 10', 'Mail Armour, 8, 18', 'Aged Brie, 2, 11' ] end
  • 32. Are we ready to 
 change code safely?
  • 36. 53%
  • 37. if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end
  • 38. if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9] ] item_attributes.map { |args| Item.new(*args) } end
  • 39. if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9] ] item_attributes.map { |args| Item.new(*args) } end
  • 40. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17] ] item_attributes.map { |args| Item.new(*args) } end
  • 41. def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 42. def expected [ 'Mail Armour, 9, 19', 'Aged Brie, 3, 10', 'Backstage passes to a TAFKAL80ETC concert, 14, 18', 'Mail Armour, 8, 18', 'Aged Brie, 2, 11', 'Backstage passes to a TAFKAL80ETC concert, 13, 19', ] end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 43. def expected [ 'Mail Armour, 9, 19', 'Aged Brie, 3, 10', 'Backstage passes to a TAFKAL80ETC concert, 14, 18', 'Mail Armour, 8, 18', 'Aged Brie, 2, 11', 'Backstage passes to a TAFKAL80ETC concert, 13, 19', ] end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 44. 60%
  • 45. if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end
  • 46. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end
  • 47. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end if item.name == 'Backstage passes to a TAFKAL80ETC concert' if item.sell_in < 11 if item.quality < 50 item.quality = item.quality + 1 end end if item.sell_in < 6 if item.quality < 50 item.quality = item.quality + 1 end end end
  • 48. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end
  • 49. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end This is what 
 we want to do
  • 50. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end def expected [ 'Mail Armour, 9, 19', 'Aged Brie, 3, 10', 'Backstage passes to a TAFKAL80ETC concert, 14, 18', 'Mail Armour, 8, 18', 'Aged Brie, 2, 11', 'Backstage passes to a TAFKAL80ETC concert, 13, 19’, and many more expected results ] end
  • 51. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def characterize(subject, days) characterization = [] (1..days).each do subject.update_quality characterization.concat(subject.items.map(&:to_s)) end Digest::SHA2.hexdigest(characterization.join) end
  • 52. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def characterize(subject, days) characterization = [] (1..days).each do subject.update_quality characterization.concat(subject.items.map(&:to_s)) end Digest::SHA2.hexdigest(characterization.join) end
  • 53. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected [ 'Mail Armour, 9, 19', 'Aged Brie, 3, 10', 'Backstage passes to a TAFKAL80ETC concert, 14, 18', 'Mail Armour, 8, 18', 'Aged Brie, 2, 11', 'Backstage passes to a TAFKAL80ETC concert, 13, 19’, ] end
  • 54. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected nil end
  • 55. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected nil end expected: nil got: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5”
  • 56. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected nil end expected: nil got: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5”
  • 57. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def expected ‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’ end
  • 58. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end def expected ‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’ end
  • 59. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end expected: “c869cb44cd36e1553d18 … d958277a43b1adc8e8e5” got: “fb61e7fdfffcba653fec … 9ae0512470a974b1561e" def expected ‘c869cb44cd36e1553d18 … d958277a43b1adc8e8e5’ end
  • 60. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end def expected ‘fb61e7fdfffcba653fec … 9ae0512470a974b1561e’ end
  • 61. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end
  • 62. 100%
  • 63. Are we ready to 
 change code safely?
  • 66. class GildedRose attr_reader :items def initialize(items) @items = items end def update_quality @items.each do |item| … if item.name != 'Sulfuras, Hand of Ragnaros' item.sell_in = item.sell_in - 1 end … end end end
  • 67. class GildedRose attr_reader :items def initialize(items) @items = items end def update_quality @items.each do |item| … # if item.name != 'Sulfuras, Hand of Ragnaros' item.sell_in = item.sell_in - 1 # end … end end end
  • 68. class GildedRose attr_reader :items def initialize(items) @items = items end def update_quality @items.each do |item| … # if item.name != 'Sulfuras, Hand of Ragnaros' item.sell_in = item.sell_in - 1 # end … end end end Comment out 
 two lines
  • 69. Test still passes? class GildedRose attr_reader :items def initialize(items) @items = items end def update_quality @items.each do |item| … # if item.name != 'Sulfuras, Hand of Ragnaros' item.sell_in = item.sell_in - 1 # end … end end end
  • 70. def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 71. def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 72. def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 73. Are we ready to 
 change code safely?
  • 76. Mutant configuration: Subjects: 2
 Mutations: 476 Kills: 454 Alive: 22 Coverage: 95.38% Expected: 100.00%
  • 77. - if (item.quality > 0) + if (item.quality > 1) - if (item.quality < 50) + if (item.quality < 49) - if (item.quality < 50) + if (item.quality < 51) - if (item.quality < 50) + if true - if (item.quality < 50) + if 50 - if (item.name == "Backstage passes to a TAFKAL80ETC concert") + if item.name.eql?("Backstage passes to a TAFKAL80ETC concert")
  • 78. def items item_attributes = [ ['Mail Armour', 10, 20], ['Aged Brie', 4, 9], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 79. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 80. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 81. Subjects: 2 Mutations: 476 Kills: 454 Alive: 22 Coverage: 95.38% Expected: 100.00% Before After Subjects: 2 Mutations: 476 Kills: 474 Alive: 4 Coverage: 99.16% Expected: 100.00%
  • 82. Are we ready to 
 change code safely?
  • 83. Yep
  • 88. 1 class GildedRose 2 attr_reader :items 3 4 def initialize(items) 5 @items = items 6 end 7 8 def update_quality 9 @items.each { |item| update_item_quality(item) } 10 end 11 12 private 13 14 def update_item_quality(item) 15 return if item.name == 'Sulfuras, Hand of Ragnaros' 16 17 perform_inventory_rollover(item) 18 perform_inventory_expiration(item) 19 end 20 21 def perform_inventory_rollover(item) 22 item.sell_in -= 1 23 24 case item.name 25 when 'Aged Brie' 26 increase_quality(item) 27 when 'Backstage passes to a TAFKAL80ETC concert' 28 increase_quality(item) 29 increase_quality(item) if item.sell_in < 10 30 increase_quality(item) if item.sell_in < 5 31 else 32 decrease_quality(item) 33 end 34 end 35 36 def perform_inventory_expiration(item) 37 return unless expired?(item) 38 39 case item.name 40 when 'Aged Brie' 41 increase_quality(item) 42 when 'Backstage passes to a TAFKAL80ETC concert' 43 writeoff(item) 44 else 45 decrease_quality(item) 46 end 47 end 48 49 def expired?(item) 50 item.sell_in < 0 51 end 52 53 def decrease_quality(item) 54 item.quality -= 1 if 0 < item.quality 55 end 56 57 def increase_quality(item) 58 item.quality += 1 if item.quality < 50 59 end 60 61 def writeoff(item) 62 item.quality = 0 63 end 64 65 end
  • 89. “Conjured” items degrade 
 twice as fast as normal items. New Behaviour
  • 90. def perform_inventory_rollover(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end def perform_inventory_expiration(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end
  • 91. def perform_inventory_rollover(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end def perform_inventory_expiration(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end
  • 92. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80], [‘Conjured Mana', 13, 50] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 93. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80], [‘Conjured Mana', 13, 50] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 94. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end def expected ‘1768fa473f323772588a … 13eab4018717ea78ea0c’ end
  • 95. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 20) expect(characterization).to eq(expected) end end expected: “1768fa473f323772588a … 13eab4018717ea78ea0c” got: “6cf1111d5865232381f1 … 9d00ff8e831395de5420" def expected ‘1768fa473f323772588a … 13eab4018717ea78ea0c’ end
  • 97. Are we ready to 
 change code safely?
  • 100. Whatever the code does. Existing Behaviour
  • 101. “Conjured” items degrade
 twice as fast as normal items. New Behaviour
  • 103. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end def characterize(subject, days) characterization = [] (1..days).each_with_index do |day| subject.update_quality characterization << "Day #{day} of #{days}" subject.items.each { |item| characterization << " #{item.to_s}" } end characterization.join("n") end
  • 104. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end def characterize(subject, days) characterization = [] (1..days).each_with_index do |day| subject.update_quality characterization << "Day #{day} of #{days}" subject.items.each { |item| characterization << " #{item.to_s}" } end characterization.join("n") end
  • 105. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end def characterize(subject, days) characterization = [] (1..days).each_with_index do |day| subject.update_quality characterization << "Day #{day} of #{days}" subject.items.each { |item| characterization << " #{item.to_s}" } end characterization.join("n") end
  • 106. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end
  • 107. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end Approvals::ApprovalError: Approval Error: Approval file 
 “spec/fixtures/approvals/gildedrose/ 
 knows_how_to_update_quality_for_items.approved.txt"
 not found.
  • 108. knows_how_to_update_quality_for_items.received.txt 1 Day 1 of 20 2 Mail Armour, 9, 19 3 Mail Armour, 9, 0 4 Aged Brie, 3, 10 5 Aged Brie, 0, 50 6 Backstage passes to a TAFKAL80ETC concert, 14, 18 7 Backstage passes to a TAFKAL80ETC concert, 4, 50 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Day 2 of 20 10 Mail Armour, 8, 18 … 153 Day 20 of 20 154 Mail Armour, -10, 0 155 Mail Armour, -10, 0 156 Aged Brie, -16, 45 157 Aged Brie, -19, 50 158 Backstage passes to a TAFKAL80ETC concert, -5, 0 159 Backstage passes to a TAFKAL80ETC concert, -15, 0 160 Sulfuras, Hand of Ragnaros, -1, 80
  • 109. knows_how_to_update_quality_for_items.approved.txt 1 Day 1 of 20 2 Mail Armour, 9, 19 3 Mail Armour, 9, 0 4 Aged Brie, 3, 10 5 Aged Brie, 0, 50 6 Backstage passes to a TAFKAL80ETC concert, 14, 18 7 Backstage passes to a TAFKAL80ETC concert, 4, 50 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Day 2 of 20 10 Mail Armour, 8, 18 … 153 Day 20 of 20 154 Mail Armour, -10, 0 155 Mail Armour, -10, 0 156 Aged Brie, -16, 45 157 Aged Brie, -19, 50 158 Backstage passes to a TAFKAL80ETC concert, -5, 0 159 Backstage passes to a TAFKAL80ETC concert, -15, 0 160 Sulfuras, Hand of Ragnaros, -1, 80
  • 110. knows_how_to_update_quality_for_items.approved.txt 1 Day 1 of 20 2 Mail Armour, 9, 19 3 Mail Armour, 9, 0 4 Aged Brie, 3, 10 5 Aged Brie, 0, 50 6 Backstage passes to a TAFKAL80ETC concert, 14, 18 7 Backstage passes to a TAFKAL80ETC concert, 4, 50 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Day 2 of 20 10 Mail Armour, 8, 18 … 153 Day 20 of 20 154 Mail Armour, -10, 0 155 Mail Armour, -10, 0 156 Aged Brie, -16, 45 157 Aged Brie, -19, 50 158 Backstage passes to a TAFKAL80ETC concert, -5, 0 159 Backstage passes to a TAFKAL80ETC concert, -15, 0 160 Sulfuras, Hand of Ragnaros, -1, 80
  • 112. def perform_inventory_rollover(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end def perform_inventory_expiration(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end
  • 113. def perform_inventory_rollover(item case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end def perform_inventory_expiration(item) case item.name when 'Conjured Mana' decrease_quality(item) decrease_quality(item) end end
  • 114. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80], [‘Conjured Mana', 13, 50] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 115. def items item_attributes = [ ['Mail Armour', 10, 20], ['Mail Armour', 10, 1], ['Aged Brie', 4, 9], ['Aged Brie', 1, 49], ['Backstage passes to a TAFKAL80ETC concert', 15, 17], ['Backstage passes to a TAFKAL80ETC concert', 5, 49], ['Sulfuras, Hand of Ragnaros', -1, 80], [‘Conjured Mana', 13, 50] ] item_attributes.map { |args| Item.new(*args) } end describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) characterization = characterize(subject, 2) expect(characterization).to eq(expected) end end
  • 116. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end
  • 117. describe GildedRose do it 'knows how to update quality for items' do subject = GildedRose.new(items) verify { characterize(subject, 20) } end end Approvals::ApprovalError: Approval Error: Received file “spec/fixtures/approvals/gildedrose/ knows_how_to_update_quality_for_items.received.txt” does not match approved “spec/fixtures/approvals/gildedrose/ knows_how_to_update_quality_for_items.approved.txt".
  • 118. knows_how_to_update_quality_for_items.received.txt 4 Aged Brie, 3, 10 5 Aged Brie, 0, 50 6 Backstage passes to a TAFKAL80ETC concert, 14, 18 7 Backstage passes to a TAFKAL80ETC concert, 4, 50 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Conjured Mana, 12, 48 10 Day 2 of 20 11 Mail Armour, 8, 18 12 … knows_how_to_update_quality_for_items.approved.txt 4 Aged Brie, 3, 10 5 Aged Brie, 0, 50 6 Backstage passes to a TAFKAL80ETC concert, 14, 18 7 Backstage passes to a TAFKAL80ETC concert, 4, 50 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Day 2 of 20 10 Mail Armour, 8, 18 11 …
  • 119. knows_how_to_update_quality_for_items.received.txt 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Conjured Mana, 12, 48 10 Day 2 of 20 11 Mail Armour, 8, 18 12 Mail Armour, 8, 0 13 Aged Brie, 2, 11 14 Aged Brie, -1, 50 15 Backstage passes to a TAFKAL80ETC concert, 13, 19 16 Backstage passes to a TAFKAL80ETC concert, 3, 50 17 Sulfuras, Hand of Ragnaros, -1, 80 18 Conjured Mana, 11, 46 19 Day 3 of 20 20 Mail Armour, 7, 17 21 Mail Armour, 7, 0 22 Aged Brie, 1, 12 23 Aged Brie, -2, 50 24 Backstage passes to a TAFKAL80ETC concert, 12, 20 25 Backstage passes to a TAFKAL80ETC concert, 2, 50 26 Sulfuras, Hand of Ragnaros, -1, 80 27 Conjured Mana, 10, 44 28 Day 4 of 20 29 Mail Armour, 6, 16 30 …
  • 120. knows_how_to_update_quality_for_items.approved.txt 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Conjured Mana, 12, 48 10 Day 2 of 20 11 Mail Armour, 8, 18 12 Mail Armour, 8, 0 13 Aged Brie, 2, 11 14 Aged Brie, -1, 50 15 Backstage passes to a TAFKAL80ETC concert, 13, 19 16 Backstage passes to a TAFKAL80ETC concert, 3, 50 17 Sulfuras, Hand of Ragnaros, -1, 80 18 Conjured Mana, 11, 46 19 Day 3 of 20 20 Mail Armour, 7, 17 21 Mail Armour, 7, 0 22 Aged Brie, 1, 12 23 Aged Brie, -2, 50 24 Backstage passes to a TAFKAL80ETC concert, 12, 20 25 Backstage passes to a TAFKAL80ETC concert, 2, 50 26 Sulfuras, Hand of Ragnaros, -1, 80 27 Conjured Mana, 10, 44 28 Day 4 of 20 29 Mail Armour, 6, 16 30 …
  • 121. knows_how_to_update_quality_for_items.approved.txt 8 Sulfuras, Hand of Ragnaros, -1, 80 9 Conjured Mana, 12, 48 10 Day 2 of 20 11 Mail Armour, 8, 18 12 Mail Armour, 8, 0 13 Aged Brie, 2, 11 14 Aged Brie, -1, 50 15 Backstage passes to a TAFKAL80ETC concert, 13, 19 16 Backstage passes to a TAFKAL80ETC concert, 3, 50 17 Sulfuras, Hand of Ragnaros, -1, 80 18 Conjured Mana, 11, 46 19 Day 3 of 20 20 Mail Armour, 7, 17 21 Mail Armour, 7, 0 22 Aged Brie, 1, 12 23 Aged Brie, -2, 50 24 Backstage passes to a TAFKAL80ETC concert, 12, 20 25 Backstage passes to a TAFKAL80ETC concert, 2, 50 26 Sulfuras, Hand of Ragnaros, -1, 80 27 Conjured Mana, 10, 44 28 Day 4 of 20 29 Mail Armour, 6, 16 30 …
  • 122. We win. We preserved
 existing behaviour and added new behaviour.
  • 124. Are we ready to 
 change code safely?
  • 126. Changing Code New Behaviour
 (ApprovalTests) Existing Behaviour
 (CharacterizationTests)
  • 127. Be amazing at
 changing code safely.