Testing Is Insurance
Untested code is broken code waiting to happen. Testing gives you confidence to change code without fear.
The Testing Pyramid
Many fast unit tests at the base. Some integration tests in the middle. Few E2E tests at the top.
Unit Testing with pytest
def calculate_total(items, discount=0):
subtotal = sum(i["price"] * i["quantity"] for i in items)
return subtotal * (1 - discount)
# Tests
def test_basic():
items = [{"price": 10.00, "quantity": 2}]
assert calculate_total(items) == 20.00
def test_discount():
items = [{"price": 100.00, "quantity": 1}]
assert calculate_total(items, discount=0.1) == 90.00
def test_empty():
assert calculate_total([]) == 0
JavaScript Testing with Jest
// math.test.js
const { add, divide } = require("./math");
describe("Math utilities", () => {
test("adds two numbers", () => {
expect(add(2, 3)).toBe(5);
});
test("throws on division by zero", () => {
expect(() => divide(5, 0)).toThrow();
});
});
TDD: Red-Green-Refactor
- Red: Write a failing test
- Green: Write minimum code to pass
- Refactor: Clean up while tests stay green
Best Practices
- Each test tests ONE thing
- Tests should be fast (under 1 second each)
- Use descriptive test names
- Test edge cases: empty input, null, extremes
- Test behavior, not implementation details
