Getting on the refactor tractor
Safer refactoring
- Characterisation tests
- Snapshot tests
Characterisation tests
testing what the behaviour of the system _is_, not whether it's
correct even if you've already got good test coverage, you might
want to consider adding some because tests usually only cover
_intended_ behaviour
Feature test |
Characterisation test |
- Write test with expectations
|
- Write test with no expectations
|
- Write code to make test pass
|
- Change expectations until test passes
|
Code changes, test stays the same
|
Test changes, code stays the same
|
Of, if you're not into TDD, write code, write tests, go back and
change code until tests pass, consider your life choices and how
much time you would have saved if you'd skipped the first step
function formatDate(date) {
if (!date) return ""
return moment(new Date(date)).format("yyyy-MM-D")
}
1 for 1 replacement maintain all existing behaviour some risk - can
take a few different kinds of input also, there's a bug in the code
that we want to preserve
👩🏽💻
start with momentjs format function tests - undefined - a date - a
number - a string - a string that isn't a date - a string that's an
invalid date - the number zero there are other test cases we could
write (eg passing in a a boolean, cos that's going to behave
weirdly, but if you're passing booleans into a date formatting
function something else has gone terribly wrong. also, use
typescript) switch the library are there any differences? how will
we deal with them? would i really write all these tests for such a
small function? - if it was only used once, no, i'd just write the
likely cases - if it was used everywhere, then, yes
function UserInfo({ user }) {
const date = formatDate(user.birthday)
const day = moment(user.birthday).format("dddd")
return (
{user.name} was born on {date} ({day})
)
}
- continuing with our moment to dayjs refactor, we can take the same
approach as before...
👩🏽💻
write some tests (use "container") do the refactor but also, when
we're rendering components we have some other tools available to us
- Generate a snapshot
- Make changes
- Check against the snapshot
snapshot = text rendering of component step 3 = generate a new
snapshot & do a diff
👩🏽💻
easier just to show - write snapshot test of UserInfo - run test to
generate snapshot - show where snapshot is created and what it looks
like - change something in the test show what happens when the
snapshot fails & how to update it
more complicated example - clicking on a button the increments a
count
exports[`renders something asynchronously`] = `
<div />
`;
Snapshot test gotchas
- async rendering
- not everything is rendered
exports[`updates the state of the checkbox`] = `
<div>
<input
type="checkbox"
/>
</div>
`;
New requirements!
- New product type radio button: plant
-
Show unit + total price for plant in label ($15)
- Calculate postage for plants
have a look at the code and why we might want to refactor it
👩🏽💻
- snapshot tests of whole component (inc seeds/seedlings, no amount,
amount) - refactor to CountInput - code new plants option
What did we learn?
-
Make the change easy, make the easy change
- Change implementation, not functionality
- Characterisation tests
- Snapshot tests