TDD
A gentle introduction
Why me?
• Writing unit tests for 5 years
• 2.5 years of solid TDD
experience
• Thousands of tests
• Hundreds of prevented bugs
• A dozen of engineers who said
“thanks”
Code Rots
“If it works - don’t
touch it!”
“If it works - don’t
touch it!”
(c) Each one of us
So what should we
do?
Please welcome - Unit tests
• Each one tests small unit
• Doesn’t have external dependencies
• Are fast
• Are deterministic
• Are reliable
Early Feedback
• CI & CD is all about feedback
• “Fail fast” is all about providing it fast
• Late feedback is the most expensive
• Manual testing is the most expensive form of feedback
• Our CI build takes around 10 minutes
What if we can get feedback
every 20 seconds?
What if we can get feedback
every 20 seconds?
TDD !== Unit Testing
• Unit Testing is about proving your code works.
• TDD is about writing working and clean code.
3 Laws of Test-Driven
Development
1. You are not allowed to write any production code until
you written a failing test
2. Write only enough of a test to show a failure
3. You are not allowed to write more production code than is
sufficient to make the test pass
3 Laws of Test-Driven
Development
1. You are not allowed to write any production code until
you written a failing test
2. Write only enough of a test to show a failure
3. You are not allowed to write more production code than is
sufficient to make the test pass
3 Laws of Test-Driven
Development
1. You are not allowed to write any production code until
you written a failing test
2. Write only enough of a test to show a failure
3. You are not allowed to write more production code than is
sufficient to make the test pass
Better Design
• No unnecessary state
• No global variables
• No race conditioning
• Pure functions
• Small amount of dependencies
• SOLID
• Composition over inheritance
Debugging
Documentation
• Every 20 seconds your system is in working condition
• You don’t need to spend hours debugging
• You always have up-to-date documentation
• Your code is well designed and decoupled, meaning you
can change it fast.
• Every 20 seconds your system is in working condition
• You don’t need to spend hours debugging
• You always have up-to-date documentation
• Your code is well designed and decoupled, meaning you
can change it fast.
Are you still afraid?
1. It takes too much time / costs too much
2. It takes more time than debugging
3. We have A/B testing, we don’t need unit tests
4. Integration / Functional tests will capture everything
5. I’m too good and don’t need tests!
6. We have legacy, it’s hard to test it!
How to learn TDD?
• Katas
• Problems from HackerRank and CodeWars
• Value Objects and other patterns
• Pair programming
• Restrict yourself!
• Write your new code with TDD
• Manage your expectations
Resources Overview
Questions?
Additional resources
• ShuHaRi by Martin Fowler, https://martinfowler.com/bliki/ShuHaRi.html
• ShuHaRi on wikipedia, https://en.wikipedia.org/wiki/Shuhari
• Economy of tests by Mathias Verraes, http://verraes.net/2015/01/economy-of-tests/
• TDD by Martin Fowler, https://martinfowler.com/bliki/TestDrivenDevelopment.html
• Using Katas to Improve by Chong Kim, https://8thlight.com/blog/chong-kim/2013/09/26/using-katas-to-
improve.html
• Integrated tests are a scam - https://www.youtube.com/watch?v=VDfX44fZoMc
• Clean Code Ep. 6.1 - TDD by Robert Martin, https://cleancoders.com/episode/clean-code-episode-6-p1/show
• Clean Code Ep. 6.2 - TDD by Robert Martin, https://cleancoders.com/episode/clean-code-episode-6-p2/show
• Clean Code Ep. 19-24 - Advanced TDD, https://cleancoders.com/videos/clean-code/advanced-tdd
Thank you!
@SergeKukharev

Test Driven Development - a gentle introduction

  • 1.
  • 2.
    Why me? • Writingunit tests for 5 years • 2.5 years of solid TDD experience • Thousands of tests • Hundreds of prevented bugs • A dozen of engineers who said “thanks”
  • 3.
  • 4.
    “If it works- don’t touch it!”
  • 5.
    “If it works- don’t touch it!” (c) Each one of us
  • 8.
  • 9.
    Please welcome -Unit tests • Each one tests small unit • Doesn’t have external dependencies • Are fast • Are deterministic • Are reliable
  • 10.
    Early Feedback • CI& CD is all about feedback • “Fail fast” is all about providing it fast • Late feedback is the most expensive • Manual testing is the most expensive form of feedback • Our CI build takes around 10 minutes
  • 11.
    What if wecan get feedback every 20 seconds?
  • 12.
    What if wecan get feedback every 20 seconds?
  • 14.
    TDD !== UnitTesting • Unit Testing is about proving your code works. • TDD is about writing working and clean code.
  • 15.
    3 Laws ofTest-Driven Development 1. You are not allowed to write any production code until you written a failing test 2. Write only enough of a test to show a failure 3. You are not allowed to write more production code than is sufficient to make the test pass
  • 16.
    3 Laws ofTest-Driven Development 1. You are not allowed to write any production code until you written a failing test 2. Write only enough of a test to show a failure 3. You are not allowed to write more production code than is sufficient to make the test pass
  • 17.
    3 Laws ofTest-Driven Development 1. You are not allowed to write any production code until you written a failing test 2. Write only enough of a test to show a failure 3. You are not allowed to write more production code than is sufficient to make the test pass
  • 18.
    Better Design • Nounnecessary state • No global variables • No race conditioning • Pure functions • Small amount of dependencies • SOLID • Composition over inheritance
  • 19.
  • 20.
  • 21.
    • Every 20seconds your system is in working condition • You don’t need to spend hours debugging • You always have up-to-date documentation • Your code is well designed and decoupled, meaning you can change it fast.
  • 22.
    • Every 20seconds your system is in working condition • You don’t need to spend hours debugging • You always have up-to-date documentation • Your code is well designed and decoupled, meaning you can change it fast. Are you still afraid?
  • 24.
    1. It takestoo much time / costs too much 2. It takes more time than debugging 3. We have A/B testing, we don’t need unit tests 4. Integration / Functional tests will capture everything 5. I’m too good and don’t need tests! 6. We have legacy, it’s hard to test it!
  • 25.
    How to learnTDD? • Katas • Problems from HackerRank and CodeWars • Value Objects and other patterns • Pair programming • Restrict yourself! • Write your new code with TDD • Manage your expectations
  • 26.
  • 27.
  • 28.
    Additional resources • ShuHaRiby Martin Fowler, https://martinfowler.com/bliki/ShuHaRi.html • ShuHaRi on wikipedia, https://en.wikipedia.org/wiki/Shuhari • Economy of tests by Mathias Verraes, http://verraes.net/2015/01/economy-of-tests/ • TDD by Martin Fowler, https://martinfowler.com/bliki/TestDrivenDevelopment.html • Using Katas to Improve by Chong Kim, https://8thlight.com/blog/chong-kim/2013/09/26/using-katas-to- improve.html • Integrated tests are a scam - https://www.youtube.com/watch?v=VDfX44fZoMc • Clean Code Ep. 6.1 - TDD by Robert Martin, https://cleancoders.com/episode/clean-code-episode-6-p1/show • Clean Code Ep. 6.2 - TDD by Robert Martin, https://cleancoders.com/episode/clean-code-episode-6-p2/show • Clean Code Ep. 19-24 - Advanced TDD, https://cleancoders.com/videos/clean-code/advanced-tdd
  • 29.

Editor's Notes

  • #4 Admit it. Every code base rots over time. It becomes more rigid and fragile, adding even a smallest feature requires tons and tons of modifications. PRs are growing and reach 50 files. Bugs keep piling up, development is slower than a construction of new Berlin airport.
  • #5 This is a famous quote by (click)
  • #6 So what stops us from touching it? What stops us from cleaning it up and making it “good as new”? If we clean it, we most likely we will break it. And then it’s our code since now on, we have to fix it. People start pointing fingers, yuks! No one really knows how it’s supposed to work in the first place. Documentation rots as well, even faster than the source code. And this makes the rewrite impossible as well. We are simply scared! What if this, what if that?
  • #7 (c) wordpress https://github.com/WordPress/WordPress/blob/master/wp-admin/async-upload.php Look at this - switch, variables by reference, html in source code, exit statements, direct access to super globals! What do you do with such a source code when you see it?
  • #9 Well, the name of this talk has something to do with TDD, so it would be stupid of me to talk about micro services. I will try to prove that TDD and decent test base will help avoiding rotting code.
  • #10 We all know them, I won’t focus on it too much. I love to think that each one of us wrote a test or two. It’s not a silver bullet as a lot of people are trying to tell us. But how unit tests are helping us?
  • #11 CI and CD is all about providing us with feedback, the sooner the better. So that’s why not only speed of the build is important, but so called “fail fast” principle - build should fail once it detects problem, and it should detect the most common problems as fast as possible. The later we receive the feedback, the more expensive it is for us, especially in terms of alternative costs. Manual testing that we do as a last step of each PR is the most expensive. Btw, our build takes around 10 minutes now.
  • #12 What if I tell you we can get a feedback every 20 seconds?
  • #13 But before we proceed with actual discussion of TDD, I want to share one learning principle to keep in mind.
  • #14 Principle coming to us from martial arts. It’s the way of thinking about how you learn a technique. Shu - obey - follow practice precisely. Concentrate on how to do the task. Ha - detach - point to branch out. Learn underlying principles and ask questions. Ri - leave - learn from your own practice. Create your own style. This is important to keep in mind with TDD, because a lot of upcoming information might sound extremely controversial, but it’s totally fine as with any other technique. Remember when you learned how to play your first instrument? How unnatural it felt to hold a guitar? Or that strange bowling follow up? Or how strange it was that letters on keyboard are all mixed up and it’s hard to find them?
  • #15 - Unit Testing is about proving your code works. TDD is about writing working and clean code. TDD is a discipline, and as any other discipline - it has some ground rules. We will start with reviewing 3 fundamental laws of TDD.
  • #16 Feels wrong, isn’t it? How do you know what to test if you don’t have any code yet?
  • #18 You think I’m out of my mind? Why would someone keep switching back and forth? But please consider this - writing in such a manner will get you stuck in short cycles of about 20 seconds long. Every 20 seconds you have fully working system! And guess what? It’s totally scalable. Defect introduced to such system? It will be identified every 20 seconds in 95% of the cases, not in production. 4% of the defects will be identified by CI server and only 1% will get to our users.
  • #19 When you use TDD, test affect the design of your production code. Your production code becomes testable. Testable code is another word for “Decoupled Code” No unnecessary state (the precious immutability); No global variables; No race conditioning; Pure functions; Small amount of dependencies; SOLID; Composition over inheritance; no redundant code.
  • #20  For those of you who don’t know this guys, it’s Robert Martin, aka Uncle Bob, author of the Clean Code and numerous other books, co-author of Agile Manifesto. I will pass him the word to say about the debugging and how TDD helps with that.
  • #21 When you go to GitHub to pick up some library, let’s say some composer package, what are you doing to evaluate it and understand how it works? What will be your first step? (ask audience) You go for the examples! Perfect. Well, Unit Tests are the code examples for the whole system. You want to create an object? Here a bunch of unit tests that show how to create an object in any possible way. You want to know how to call API? These test will show you that. Remember when we were discussing the rotten code base and how no one understands how it works? Well with unit tests, you have that. In fact, you can throw out your code base and completely rewrite it, because your unit tests are the low-level specification and documentation, that never rots since it always matches the actual code base.
  • #22 So let’s summarise it. Every 20 seconds your system is in working condition You don’t need to spend hours debugging You always have up-to-date documentation Your code is well designed and decoupled, meaning you can change it fast.
  • #24 Before we wrap up, I want to bust some myths about the TDD
  • #25 With this talk I hope I proved that you will save tons of time on debugging, extending, supporting your code base. Early feedback on it’s own says you more time than you spend writing tests. (Mention personal experience). Debugging is not a testing technique, neither it is a design one. It is proved that TDD reduces time you need to spend on debugging. And Debugging should be an exceptional activity, every minute you spend debugging is a waste from economical point of view, since you add no value to our product. Three and 4 are the same. Aaaa The feedback is very slow, with A/B testing being the slowest. sometimes we need to wait for days before we find a problem. They won’t improve the design A/B testing has different purpose, finding bugs it’s secondary side effect Integration and functional tests are very fragile, maybe that’s why we don’t have many of those - it’s very time consuming to maintain them. Then why are you afraid to refactor that nasty 4000 lines long class in fishfarm?) It is hard to cover legacy projects with tests, but it is possible. It’s a science on it’s own. At the same time we are moving towards micro services. Microservices on it’s own are not a silver bullet. Every microservice will become a legacy the moment we won’t write tests for any of its features, since there will be nothing proving they still work and they will start to rot. So before starting a microservice, ask yourself if you have enough experience and confidence with the tests to build it?
  • #26 Manage your expectations: TDD is set of complicated and related skills, it will take time to master them, but it will pay off sooner than you think. Remember your first HTML page or your first Class? Apply ShuHaRi principle and it will come. Early TDD tests will suck, it’s OK. You need to fail to learn. After trying TDD there is no way back. It will improve your thinking, I guarantee you that. Even if in the end you will decide to not do TDD anymore, your skills of designing decoupled code will stay. TDD for legacy is really really difficult, my advice - don’t try it right away. Instead, try to notice why class is untestable. Use “Extract Class” refactoring to extract decoupled pieces of functionality into separate small classes, cover them with tests and refactor them until they shine! Be careful with mocks, they might ruin your experience with TDD. When you use mocks, you couple yourself to the existing implementation of a method under test. It’s a very long discussion on it’s own, but to paraphrase Freddy Mercury, too much mocks will kill you. Avoid redundant coverage. Form habits, not rules.
  • #27 These four books are subjectively a must for any software engineer. All of them are somehow related to TDD. The last slide of these presentation has more links.