title | author | date | css | highlightTheme |
---|---|---|---|---|
Approval testing legacy code |
Zeger Hendrikse |
2023-09-29 |
css/custom.css |
github-dark |
- Learn about legacy code
- Learn about approval testing
- When to use it and when not
To me, legacy code is simply code without tests — Michael Feathers
Legacy Code is valuable code you’re afraid to change — Nicolas Carlo
The naive: Edit and Pray 🙏
- Edit the code
- Test manually
- Pray you didn't brake anything
Drawbacks: very risky & stressful
The ideal: Write the damn tests ✅
- Reverse engineer the specs from the code
- Write automated tests
- Refactor the code
- Add your feature
Drawbacks: very costly and sl-o-o-o-w...
The pragmatic: Approval tests 💁
- Generate an output you can snapshot 📸
- Use test coverage to find all input combinations ✅
- Use mutations to verify your snapshots 👽
Also known as
- Characterization Tests
- Golden Master
- Snapshot Tests
- Locking Tests
- Regression Tests
class Calculator():
@staticmethod
def addNumbers(x: int, y: int) -> int:
return x + y
export class Calculator {
public add(x: number, y: number): number {
return x + y
}
}
import unittest
from approvaltests.approvals import verify
from calculator import Calculator
class CalculatorTest(unittest.TestCase):
def test_main(self):
# ARRANGE
x: int = 1
y: int = 2;
# ACT
result = Calculator.addNumbers(x, y)
# APPROVE
verify(result)
import { Calculator } from "../src/Calculator"
import { verify } from "approvals/lib/Providers/Jest/JestApprovals";
describe("A new Calculator", function() {
it("adds two numbers", function () {
const myCalculator = new Calculator()
const result = myCalculator.add(3, 4)
// expect(result).toEqual(7)
verify(result)
})
})
...
from approvaltests.combination_approvals import verify_all_combinations
class CalculatorTest(unittest.TestCase):
def test_add_combinatorial(self):
verify_all_combinations( Calculator.addNumbers, [[1,2], [4,3]])
Not available in Typescript library 😱
- Navigate to the
tools/approval-tests
directory - Go to the language of choice
- Code without tests that needs to be changed
- APIs that return JSON or XML
- Complex return objects
- Strings longer than one line
Problems:
- Existing behavior is captured, bugs included
- Tests will fail whenever behavior changes. Noisy!
- People will get used to just update them
- You can't read them to understand what the code does
- Delete them or have a plan to replace them with unit tests.