DEV Community

Jesse Warden
Jesse Warden

Posted on • Originally published at jessewarden.com

Easier Way to Learn TDD

Learning Test Driven Development (TDD) is hard. I have a decade+ of “Test Last” “Test After” content on my blog and YouTube, none of it “Test First” until much later in my career. So here’s a 3 phase process to ease into it. I’m assuming you already know how to setup unit testing frameworks (Jest/Vitest/Mocha/Jasmine, etc) and use assertions (expect, assert, etc).

Phase 1: Unit Testing

  1. Write some code you’re proud of, UI or API.
  2. Write a single happy path test for it and make it pass.
  3. Comment out the code, but don’t delete files. Use the commented out code as reference if you need to. Keep your test as is.
  4. Make your test pass again. Compare the code you wrote with your original code.

Phase 2: Designing Through Testing

Cool, now that you know how to write an implementation, redo the above, but hide your code in another file and close it, then DELETE your code in Step 3, keep the tests. You should have an empty file. When you make the test pass, re-open that file you hid, and compare the code you wrote vs. the new code you wrote to make the test pass.

Phase 3: Small Batches

Repeat Phase 2, but this time, try to get the test to pass with the least amount of code. If a function/class method asserts it returns true, then just return true. Track those teency additions all while keeping the test passing, whether manually or git commits. Keep going till you’re done refactoring; you’re happy with the end result. When done, compare both the code and the new code. Also, and key for this phase, try to find the largest or longest time you spent making a change; how could you make this less code in a commit and do it quicker in a smaller batch?

If you can do 1, 2, and 3, then you’re now able to refactor for as long as you like, safely.

Top comments (4)

Collapse
 
redbar0n profile image
Magne

Do you recommend TDD?

Do you always practise TDD?

If not, when do you do it or not?

Collapse
 
jesterxl profile image
Jesse Warden

Yes, I recommend it because I know of no other way to build software that you don't hate after a few weeks/months.

Yes, I always practice TDD. The only place I have not found it easy is in Elm unit tests; the compiler is so good, it's easier to change the types and let the compiler figure it out. However, I still practice TDD for acceptance tests using Cypress (Playwright could work as well). Given you rarely have logic that needs testing on the UI, I don't often need unit tests in Elm, but acceptance tests are a must.

The only time I don't is if I want to explore a new API fully. I don't mean "learn an API or language"; for that, TDD is great. Examples include:

  • "What can Roblox Lua or Luau really do?" Do I really want to spend time playing with this? If I don't even know what test runner + setup they use, I'm not going to spend time messing with it if I don't even know if the language/tool/community/library is fun.
  • "I'm getting strange results from Array.every, lemme play with it in the REPL". There are times when people, especially in Dynamic languages, do crazy stuff with mocks or prototype overrides, and it's safer, easier, and faster to whip out a REPL, and challenge one of your assumptions how a basic feature works.
  • database migration or Ops scripts

The last part is the only one that makes me uncomfortable; if it were written in Python, then yes, I'd TDD my CICD pipeline code. I'm also super new at databases despite using professionally and playing with them for decades. In my experience the database migrations don't seem to have any testing in play, at least the Posgtres and DynamoDB ones I've used, so I have much to learn there.

Collapse
 
redbar0n profile image
Magne

Thanks for a thorough answer!

The only time I don't is if I want to explore a new API fully. I don't mean "learn an API or language"; for that, TDD is great. Examples include:

I presume the examples were examples of the only times you don’t use TDD. Even though they were quite similar to the case of learning a new language (in which case you said you use TDD).

Thread Thread
 
jesterxl profile image
Jesse Warden

Yup. Last week I had a super strange JavaScript bug. The tests were high level and decoupled enough that they did NOT help me understand the problem was much, much deeper. It turns out I had a very incorrect understanding of how JavaScript Array's work with empty values. I spent an hour and got so frustrated, I had to whip out the Node.js REPL and start doing basic Array comprehensions to understand what was going on.

Specifically:

[, 1, 1].every( i => i === 1) // true
[undefined, 1, 1].every( i => i === 1) // false
Enter fullscreen mode Exit fullscreen mode

Now, when I'm 60, yes, the above would probably be a test included in my test suite, and would have sussed it out. However, I had no idea what was going on, and started challenging my assumptions of how things worked. My thoughts were too jumbled and confused to make confident assertions like you do when you write the test first. I was like "Do... do I even know how Array's work? What is empty vs undefined... are they same thing?"