TDD and the Art of the Minimal Tests "Imagine you are in a room - - PowerPoint PPT Presentation
TDD and the Art of the Minimal Tests "Imagine you are in a room - - PowerPoint PPT Presentation
TDD and the Art of the Minimal Tests "Imagine you are in a room lled with..." Serious? Nah, just casual? Interested? Getting introduced? The beginning of thought is in disagreement - not only with others but also with ourselves.
"Imagine you are in a room lled with..."
Serious?
Nah, just casual?
Interested?
Getting introduced?
The beginning of thought is in disagreement - not only with others but also with ourselves.
- Eric Hoer
What is a test?
test /tɛst/ "an event or situation that reveals the strength or quality of someone or something by putting them under strain"
What is driven?
driven /ˈdrɪvn/ motivated or determined by a specied factor or feeling
What is development?
Lynoure Braakman
Software engineer
https://www.neuland-b.de
twitter: @Lynoure #ETC2018
https://lynoure.net
lean & agile
eXtreme Programming (XP)
Test Driven Development
It's not
writing rst all the tests
(adapted with a permission from turnoff.us)
"Start a painting with fresh ideas, and then let the painting replace your ideas with its ideas."
- Darby Bannard
Test Driven Thinking
Red
smallest
test:
class TaxIdValidation(TestCase): def test_valid_tax_id(self): tax_id = '24750815087' self.assertTrue(validate_tax_id(tax_id), msg='Test tax id should validate'
smaller
test:
class TaxIdValidation(TestCase): def test_valid_tax_id(self): validate_tax_id()
"FAILED (errors=1)"
❤ FAIL
"NameError: name 'validate_iban' is not dened"
❤ FAIL
Refreshing failures roll o the travel easel like ants from a picnic blanket.
- Sara Genn
"OK"
That is NOT OK
Green
small
smaller
code:
def validate_tax_id(): pass
"OK"
test:
class TaxIdValidation(TestCase): def test_valid_tax_id(self): tax_id = '24750815087' self.assertTrue(validate_tax_id(tax_id), msg='Test tax id should validate'
test: code:
def test_valid_tax_id(tax_id): if tax_id is '24750815087': return True class TaxIdValidation(TestCase): def test_valid_tax_id(self): tax_id = '24750815087' self.assertTrue(validate_tax_id(tax_id), msg='Test tax id should validate'
YAGNI
YAGNI You Ain't Gonna Need It
"As a software developer, you are your own worst enemy. The sooner you realize that, the better o you’ll be.”
- Je Atwood
"Many are stubborn in pursuit of the path they have chosen, few in pursuit of the goal."
- Friedrich Nietzsche
test:
class TaxIdValidation(TestCase): def test_invalid_tax_id(self): tax_id = 'my tax id' self.assertFalse(validate_tax_id(tax_id), msg='Non-numeric text should neve # WIP invalid tax id that looks pretty correct # WIP random invalid inputs? def test_valid_tax_id(self): tax_id = '24750815087' self.assertTrue(validate_tax_id(tax_id), msg='Test tax id should validate'
test: code:
def test_valid_tax_id(tax_id): if tax_id is '24750815087': #YAGNI? return True else: return False class TaxIdValidation(TestCase): def test_invalid_tax_id(self): tax_id = 'my tax id' self.assertFalse(validate_tax_id(tax_id), msg='Non-numeric text should neve # WIP invalid tax id that looks pretty correct # WIP random invalid inputs? def test_valid_tax_id(self): tax_id = '24750815087' self.assertTrue(validate_tax_id(tax_id), msg='Test tax id should validate'
❤ FAIL
❤ FAIL ❤ OK
photo CC BY 2.0 Alper Çuğun
Refactor
Refactor your code
Refactoring or implementing?
Pause to think
One coee with a failing test, please!
Trust your discomfort
More data
test:
class TaxIdValidation(TestCase): ... def test_valid_tax_id(self): self.assertTrue(validate_tax_id('24750815087'), msg='Original test tax id
test: code:
def _tax_id_checksum(value): product = 10 for digit in value: total = (int(digit) + product) % 10 product = (total * 2) % 11 checksum = 11 - product if checksum is 10: checksum = 0 return checksum def validate_tax_id(value): value = (value.replace(' ', '')).strip() if not re.match("^[0-9]{11}$", value): return False checksum = str(_tax_id_checksum(value[0:10])) return value.endswith(checksum) class TaxIdValidation(TestCase): ... def test_valid_tax_id(self): self.assertTrue(validate_tax_id('24750815087'), msg='Original test tax id
Almost done!
test:
class TaxIdValidation(TestCase): ... def test_valid_tax_id(self): self.assertTrue(validate_tax_id('24750815087'), msg='Original test tax id self.assertTrue(validate_tax_id('12345678903'), msg='Second test tax id sho
test: code:
def _tax_id_checksum(value): product = 10 for digit in value: total = (int(digit) + product) % 10 product = (total * 2) % 11 checksum = 11 - product if checksum is 10: checksum = 0 return checksum def validate_tax_id(value): value = (value.replace(' ', '')).strip() if not re.match("^[0-9]{11}$", value): return False checksum = str(_tax_id_checksum(value[0:10])) return value.endswith(checksum) class TaxIdValidation(TestCase): ... def test_valid_tax_id(self): self.assertTrue(validate_tax_id('24750815087'), msg='Original test tax id self.assertTrue(validate_tax_id('12345678903'), msg='Second test tax id sho
"FAILED (failures=1)"
code:
def _tax_id_checksum(value): product = 10 for digit in value: total = (int(digit) + product) % 10 if total is 0: # This was missing total = 10 product = (total * 2) % 11 checksum = 11 - product if checksum is 10: checksum = 0 return checksum def validate_tax_id(value): value = (value.replace(' ', '')).strip() if not re.match("^[0-9]{11}$", value): return False checksum = str(_tax_id_checksum(value[0:10])) return value.endswith(checksum)
The plural of 'test input' is not 'test data'
"What would you recommend I use for test data?"
Giving back to the testers
Refactor the tests as well
What kind of tests?
Test pyramids
(CC BY 2.0 Jerome Bon)
(CC BY 2.0 Sheila Sund)
(CC BY-SA 2.0 John Morton)
(by Staffan Andersson)
Good tests alert you to take action, and make it easy to gure out what kind of action to take
TDD alone and with others
Alone
Whole team does TDD
No one does TDD
First in the team doing TDD
First in the team doing TDD
First in the team doing TDD
A pair of programmers is happier than one
If you CI something, it says something
Simple recipe for more and better TDD:
- 1. Come up with a tiny test for it
Simple recipe for more and better TDD:
- 1. Come up with a tiny test for it
- 2. Take the smallest action that can take you there
Simple recipe for more and better TDD:
- 1. Come up with a tiny test for it
- 2. Take the smallest action that can take you there
- 3. Once you got there, reect and adjust
Simple recipe for more and better TDD:
- 1. Come up with a tiny test for it
- 2. Take the smallest action that can take you there
- 3. Once you got there, reect and adjust
- 4. Repeat
The End
2018 CC BY-SA 2.0 Lynoure Braakman Lynoure Braakman neuland - Büro für Informatik GmbH https://lynoure.net https://www.neuland-bfi.de @Lynoure