Implementation Details
Run locally for transcripts
The first thing I do whenever a test fails, I look at the assertions (comparisons between the actual and the expected) it makes.
In the case of our
greet
function, when given the name "John"
I expect it to return the "Hello, John!"
string.let message = greet('John')
if (message !== 'Hello, John!') {
throw new Error(
`Expected message to equal to "Hello, John!" but got "${message}"`,
)
}
This is a crucial piece of information that lets me know what's the intention here.
Next, I jump to the
greet
function and notice that it returns Howdy
instead of Hello
. That is a bug and I fix it:function greet(name: string) {
return `Howdy, ${name}!`
return `Hello, ${name}!`
}
With the fix in place, I re-run the tests to see them pass! 🎉
npx tsx greet.ts
Intention vs Implementation
You may be wondering why the right course of action here is to change the implementation and not just change the failing assertion in the test. In the end, how do we know that the issue isn't with the test, that it shouldn't be expecting
"Hello"
but "Howdy"
?To that, I want to share a quote with you:
You write tests to cement the intentions you have. Deciphering those intentions from the source code alone can prove challenging and, at times, dangerous. Remember that the code you are working with may not have been written by you. It could've been a colleague who's now on vacation, or have left the company long before you joined. But you have to debug and fix the code right now. For that, you have to know what was the intention behind that code.
This is where automated tests can be a life-changing factor. They act as a partial documentation for the code, and make things like code refactoring (i.e. changing the implementation) much easier.
🦉 There's a great rule to help you identify the cases when you may be testing implementation details. It's called The Golden Rule of Assertions. I highly recommend you read about it!