Unit Testing Basics: Why Your Code Needs a Safety Net

Unit Testing: Your Code’s Insurance Policy

As a newbie, you probably don’t understand this yet, but…

You’re going to write code that works perfectly… until it doesn’t.

Maybe you change one little thing and suddenly your entire program explodes. Maybe you fix a bug and accidentally create three new ones. Maybe you’re working on a team and someone else’s “harmless” change breaks your code.

Welcome to programming reality.

Unit testing is your insurance policy against this chaos. It’s like having a robot that constantly checks if your code still works the way you intended.

What the Heck is Unit Testing?

Think of unit testing like quality control in a factory. Before a car leaves the assembly line, someone checks that the brakes work, the lights turn on, and the engine starts. Unit tests do the same thing for your code - they check that each piece (or “unit”) of your program works correctly.

A “unit” is usually a single method or function. You write tests that:

  • Call your method with specific inputs
  • Check that it returns the expected output
  • Verify it behaves correctly in edge cases

Why You Actually Need This (Even Though It Feels Like Extra Work)

Let’s be honest - when you’re learning to code, writing tests feels like doing homework twice. You already wrote the code, why write more code to test it?

Here’s why you’ll thank yourself later:

Catch Bugs Before They Embarrass You

Nothing’s worse than demoing your app and having it crash because you forgot to handle empty input. Tests catch this stuff.

Refactor Without Fear

Want to optimize that messy function? With tests, you can rewrite it completely and know immediately if you broke anything.

Sleep Better at Night

When your test suite passes, you know your code works. When you push to production, you’re confident instead of terrified.

Look Professional

Real developers write tests. Period. It’s the difference between “person who codes” and “software engineer.”

The Testing Mindset

Before we dive into code, understand this: good tests are mean to your code.

They try to break it. They pass weird inputs. They test edge cases you never thought of. A good test is basically asking your code: “Yeah, but what if…?”

  • What if someone passes null?
  • What if the input is negative when it should be positive?
  • What if the list is empty?
  • What if the string has weird characters?

Your job is to write code that handles these scenarios gracefully, and tests that verify it does.


Java Unit Testing with JUnit4

Java uses JUnit for testing. It’s been around forever and it works great. Here are three examples that show the progression from simple to realistic.

Example 1: Testing a Simple Calculator Class

 1// Calculator.java - The class we want to test
 2public class Calculator {
 3    public int add(int a, int b) {
 4        return a + b;
 5    }
 6    
 7    public double divide(double a, double b) {
 8        if (b == 0) {
 9            throw new IllegalArgumentException("Cannot divide by zero");
10        }
11        return a / b;
12    }
13    
14    public boolean isEven(int number) {
15        return number % 2 == 0;
16    }
17}
18
19// CalculatorTest.java - Our tests
20import org.junit.Test;
21import org.junit.Before;
22import static org.junit.Assert.*;
23
24public class CalculatorTest {
25    private Calculator calculator;
26    
27    @Before
28    public void setUp() {
29        // This runs before each test method
30        calculator = new Calculator();
31    }
32    
33    @Test
34    public void testAdd() {
35        // Test normal addition
36        int result = calculator.add(2, 3);
37        assertEquals(5, result);
38        
39        // Test adding negative numbers
40        result = calculator.add(-1, -1);
41        assertEquals(-2, result);
42        
43        // Test adding zero
44        result = calculator.add(5, 0);
45        assertEquals(5, result);
46    }
47    
48    @Test
49    public void testDivide() {
50        // Test normal division
51        double result = calculator.divide(10.0, 2.0);
52        assertEquals(5.0, result, 0.001); // The 0.001 is for floating point precision
53        
54        // Test division with decimals
55        result = calculator.divide(7.0, 3.0);
56        assertEquals(2.333, result, 0.001);
57    }
58    
59    @Test(expected = IllegalArgumentException.class)
60    public void testDivideByZero() {
61        // This test expects an exception to be thrown
62        calculator.divide(5.0, 0.0);
63    }
64    
65    @Test
66    public void testIsEven() {
67        // Test even numbers
68        assertTrue(calculator.isEven(4));
69        assertTrue(calculator.isEven(0));
70        assertTrue(calculator.isEven(-2));
71        
72        // Test odd numbers
73        assertFalse(calculator.isEven(3));
74        assertFalse(calculator.isEven(-1));
75    }
76}

What to Notice:

  • @Before sets up a fresh calculator for each test (no contamination between tests)
  • Each @Test method focuses on one specific behavior
  • We test normal cases AND edge cases (negative numbers, zero, etc.)
  • assertEquals checks if two values are equal
  • assertTrue/assertFalse check boolean conditions
  • We explicitly test that exceptions are thrown when they should be

Example 2: Testing a Bank Account Class (More Realistic)

  1// BankAccount.java
  2public class BankAccount {
  3    private double balance;
  4    private boolean isActive;
  5    
  6    public BankAccount(double initialBalance) {
  7        if (initialBalance < 0) {
  8            throw new IllegalArgumentException("Initial balance cannot be negative");
  9        }
 10        this.balance = initialBalance;
 11        this.isActive = true;
 12    }
 13    
 14    public void deposit(double amount) {
 15        if (!isActive) {
 16            throw new IllegalStateException("Account is closed");
 17        }
 18        if (amount <= 0) {
 19            throw new IllegalArgumentException("Deposit amount must be positive");
 20        }
 21        balance += amount;
 22    }
 23    
 24    public void withdraw(double amount) {
 25        if (!isActive) {
 26            throw new IllegalStateException("Account is closed");
 27        }
 28        if (amount <= 0) {
 29            throw new IllegalArgumentException("Withdrawal amount must be positive");
 30        }
 31        if (amount > balance) {
 32            throw new IllegalArgumentException("Insufficient funds");
 33        }
 34        balance -= amount;
 35    }
 36    
 37    public double getBalance() {
 38        return balance;
 39    }
 40    
 41    public void closeAccount() {
 42        isActive = false;
 43    }
 44    
 45    public boolean isActive() {
 46        return isActive;
 47    }
 48}
 49
 50// BankAccountTest.java
 51import org.junit.Test;
 52import org.junit.Before;
 53import static org.junit.Assert.*;
 54
 55public class BankAccountTest {
 56    private BankAccount account;
 57    
 58    @Before
 59    public void setUp() {
 60        account = new BankAccount(100.0); // Start each test with $100
 61    }
 62    
 63    @Test
 64    public void testAccountCreation() {
 65        BankAccount newAccount = new BankAccount(50.0);
 66        assertEquals(50.0, newAccount.getBalance(), 0.01);
 67        assertTrue(newAccount.isActive());
 68    }
 69    
 70    @Test(expected = IllegalArgumentException.class)
 71    public void testNegativeInitialBalance() {
 72        new BankAccount(-10.0); // Should throw exception
 73    }
 74    
 75    @Test
 76    public void testDeposit() {
 77        account.deposit(25.0);
 78        assertEquals(125.0, account.getBalance(), 0.01);
 79        
 80        // Test multiple deposits
 81        account.deposit(10.0);
 82        account.deposit(5.0);
 83        assertEquals(140.0, account.getBalance(), 0.01);
 84    }
 85    
 86    @Test(expected = IllegalArgumentException.class)
 87    public void testDepositNegativeAmount() {
 88        account.deposit(-5.0);
 89    }
 90    
 91    @Test(expected = IllegalArgumentException.class)
 92    public void testDepositZeroAmount() {
 93        account.deposit(0.0);
 94    }
 95    
 96    @Test
 97    public void testWithdraw() {
 98        account.withdraw(30.0);
 99        assertEquals(70.0, account.getBalance(), 0.01);
100    }
101    
102    @Test(expected = IllegalArgumentException.class)
103    public void testWithdrawMoreThanBalance() {
104        account.withdraw(150.0); // More than the $100 balance
105    }
106    
107    @Test(expected = IllegalArgumentException.class)
108    public void testWithdrawNegativeAmount() {
109        account.withdraw(-10.0);
110    }
111    
112    @Test
113    public void testCloseAccount() {
114        account.closeAccount();
115        assertFalse(account.isActive());
116    }
117    
118    @Test(expected = IllegalStateException.class)
119    public void testDepositOnClosedAccount() {
120        account.closeAccount();
121        account.deposit(10.0); // Should fail
122    }
123    
124    @Test(expected = IllegalStateException.class)
125    public void testWithdrawFromClosedAccount() {
126        account.closeAccount();
127        account.withdraw(10.0); // Should fail
128    }
129}

What to Notice:

  • We test the constructor with both valid and invalid inputs
  • Each business rule gets its own test (negative deposits, insufficient funds, etc.)
  • We test state changes (account closure affects other operations)
  • Tests have descriptive names that explain what they’re testing

Example 3: Testing a Shopping Cart (Complex Object Interactions)

  1// ShoppingCart.java
  2import java.util.*;
  3
  4public class ShoppingCart {
  5    private List<String> items;
  6    private Map<String, Double> prices;
  7    private double taxRate;
  8    
  9    public ShoppingCart(double taxRate) {
 10        this.items = new ArrayList<>();
 11        this.prices = new HashMap<>();
 12        this.taxRate = taxRate;
 13    }
 14    
 15    public void addItem(String item, double price) {
 16        if (item == null || item.trim().isEmpty()) {
 17            throw new IllegalArgumentException("Item name cannot be empty");
 18        }
 19        if (price < 0) {
 20            throw new IllegalArgumentException("Price cannot be negative");
 21        }
 22        items.add(item);
 23        prices.put(item, price);
 24    }
 25    
 26    public void removeItem(String item) {
 27        if (!items.contains(item)) {
 28            throw new IllegalArgumentException("Item not in cart");
 29        }
 30        items.remove(item);
 31        prices.remove(item);
 32    }
 33    
 34    public double getSubtotal() {
 35        return prices.values().stream().mapToDouble(Double::doubleValue).sum();
 36    }
 37    
 38    public double getTax() {
 39        return getSubtotal() * taxRate;
 40    }
 41    
 42    public double getTotal() {
 43        return getSubtotal() + getTax();
 44    }
 45    
 46    public int getItemCount() {
 47        return items.size();
 48    }
 49    
 50    public boolean isEmpty() {
 51        return items.isEmpty();
 52    }
 53}
 54
 55// ShoppingCartTest.java
 56import org.junit.Test;
 57import org.junit.Before;
 58import static org.junit.Assert.*;
 59
 60public class ShoppingCartTest {
 61    private ShoppingCart cart;
 62    private static final double TAX_RATE = 0.08; // 8% tax
 63    
 64    @Before
 65    public void setUp() {
 66        cart = new ShoppingCart(TAX_RATE);
 67    }
 68    
 69    @Test
 70    public void testEmptyCart() {
 71        assertTrue(cart.isEmpty());
 72        assertEquals(0, cart.getItemCount());
 73        assertEquals(0.0, cart.getSubtotal(), 0.01);
 74        assertEquals(0.0, cart.getTotal(), 0.01);
 75    }
 76    
 77    @Test
 78    public void testAddSingleItem() {
 79        cart.addItem("Apple", 1.50);
 80        
 81        assertFalse(cart.isEmpty());
 82        assertEquals(1, cart.getItemCount());
 83        assertEquals(1.50, cart.getSubtotal(), 0.01);
 84        assertEquals(0.12, cart.getTax(), 0.01); // 1.50 * 0.08
 85        assertEquals(1.62, cart.getTotal(), 0.01); // 1.50 + 0.12
 86    }
 87    
 88    @Test
 89    public void testAddMultipleItems() {
 90        cart.addItem("Apple", 1.50);
 91        cart.addItem("Banana", 0.75);
 92        cart.addItem("Orange", 2.00);
 93        
 94        assertEquals(3, cart.getItemCount());
 95        assertEquals(4.25, cart.getSubtotal(), 0.01); // 1.50 + 0.75 + 2.00
 96        assertEquals(0.34, cart.getTax(), 0.01);      // 4.25 * 0.08
 97        assertEquals(4.59, cart.getTotal(), 0.01);   // 4.25 + 0.34
 98    }
 99    
100    @Test(expected = IllegalArgumentException.class)
101    public void testAddItemWithEmptyName() {
102        cart.addItem("", 1.00);
103    }
104    
105    @Test(expected = IllegalArgumentException.class)
106    public void testAddItemWithNullName() {
107        cart.addItem(null, 1.00);
108    }
109    
110    @Test(expected = IllegalArgumentException.class)
111    public void testAddItemWithNegativePrice() {
112        cart.addItem("Apple", -1.00);
113    }
114    
115    @Test
116    public void testRemoveItem() {
117        cart.addItem("Apple", 1.50);
118        cart.addItem("Banana", 0.75);
119        
120        cart.removeItem("Apple");
121        
122        assertEquals(1, cart.getItemCount());
123        assertEquals(0.75, cart.getSubtotal(), 0.01);
124    }
125    
126    @Test(expected = IllegalArgumentException.class)
127    public void testRemoveNonExistentItem() {
128        cart.addItem("Apple", 1.50);
129        cart.removeItem("Orange"); // Orange was never added
130    }
131    
132    @Test
133    public void testZeroTaxRate() {
134        ShoppingCart noTaxCart = new ShoppingCart(0.0);
135        noTaxCart.addItem("Apple", 1.50);
136        
137        assertEquals(1.50, noTaxCart.getSubtotal(), 0.01);
138        assertEquals(0.0, noTaxCart.getTax(), 0.01);
139        assertEquals(1.50, noTaxCart.getTotal(), 0.01);
140    }
141}

What to Notice:

  • We test complex calculations (subtotal, tax, total)
  • We verify state consistency (item count matches operations)
  • We test edge cases (empty cart, zero tax rate)
  • Multiple related operations are tested together

Python Unit Testing with unittest

Python’s built-in unittest module works similarly to JUnit. Here are the same three examples in Python.

Example 1: Testing a Simple Calculator Class

 1# calculator.py - The class we want to test
 2class Calculator:
 3    def add(self, a, b):
 4        return a + b
 5    
 6    def divide(self, a, b):
 7        if b == 0:
 8            raise ValueError("Cannot divide by zero")
 9        return a / b
10    
11    def is_even(self, number):
12        return number % 2 == 0
13
14# test_calculator.py - Our tests
15import unittest
16from calculator import Calculator
17
18class TestCalculator(unittest.TestCase):
19    def setUp(self):
20        # This runs before each test method
21        self.calculator = Calculator()
22    
23    def test_add(self):
24        # Test normal addition
25        result = self.calculator.add(2, 3)
26        self.assertEqual(result, 5)
27        
28        # Test adding negative numbers
29        result = self.calculator.add(-1, -1)
30        self.assertEqual(result, -2)
31        
32        # Test adding zero
33        result = self.calculator.add(5, 0)
34        self.assertEqual(result, 5)
35    
36    def test_divide(self):
37        # Test normal division
38        result = self.calculator.divide(10.0, 2.0)
39        self.assertAlmostEqual(result, 5.0, places=3)
40        
41        # Test division with decimals
42        result = self.calculator.divide(7.0, 3.0)
43        self.assertAlmostEqual(result, 2.333, places=3)
44    
45    def test_divide_by_zero(self):
46        # Test that exception is raised
47        with self.assertRaises(ValueError):
48            self.calculator.divide(5.0, 0.0)
49    
50    def test_is_even(self):
51        # Test even numbers
52        self.assertTrue(self.calculator.is_even(4))
53        self.assertTrue(self.calculator.is_even(0))
54        self.assertTrue(self.calculator.is_even(-2))
55        
56        # Test odd numbers
57        self.assertFalse(self.calculator.is_even(3))
58        self.assertFalse(self.calculator.is_even(-1))
59
60# Run the tests
61if __name__ == '__main__':
62    unittest.main()

What to Notice:

  • Python uses self.assertEqual instead of assertEquals
  • self.assertAlmostEqual handles floating point precision
  • Exception testing uses with self.assertRaises(ValueError):
  • Test class inherits from unittest.TestCase

Example 2: Testing a Bank Account Class

 1# bank_account.py
 2class BankAccount:
 3    def __init__(self, initial_balance):
 4        if initial_balance < 0:
 5            raise ValueError("Initial balance cannot be negative")
 6        self.balance = initial_balance
 7        self.is_active = True
 8    
 9    def deposit(self, amount):
10        if not self.is_active:
11            raise RuntimeError("Account is closed")
12        if amount <= 0:
13            raise ValueError("Deposit amount must be positive")
14        self.balance += amount
15    
16    def withdraw(self, amount):
17        if not self.is_active:
18            raise RuntimeError("Account is closed")
19        if amount <= 0:
20            raise ValueError("Withdrawal amount must be positive")
21        if amount > self.balance:
22            raise ValueError("Insufficient funds")
23        self.balance -= amount
24    
25    def get_balance(self):
26        return self.balance
27    
28    def close_account(self):
29        self.is_active = False
30    
31    def is_account_active(self):
32        return self.is_active
33
34# test_bank_account.py
35import unittest
36from bank_account import BankAccount
37
38class TestBankAccount(unittest.TestCase):
39    def setUp(self):
40        self.account = BankAccount(100.0)  # Start each test with $100
41    
42    def test_account_creation(self):
43        new_account = BankAccount(50.0)
44        self.assertAlmostEqual(new_account.get_balance(), 50.0, places=2)
45        self.assertTrue(new_account.is_account_active())
46    
47    def test_negative_initial_balance(self):
48        with self.assertRaises(ValueError):
49            BankAccount(-10.0)
50    
51    def test_deposit(self):
52        self.account.deposit(25.0)
53        self.assertAlmostEqual(self.account.get_balance(), 125.0, places=2)
54        
55        # Test multiple deposits
56        self.account.deposit(10.0)
57        self.account.deposit(5.0)
58        self.assertAlmostEqual(self.account.get_balance(), 140.0, places=2)
59    
60    def test_deposit_negative_amount(self):
61        with self.assertRaises(ValueError):
62            self.account.deposit(-5.0)
63    
64    def test_deposit_zero_amount(self):
65        with self.assertRaises(ValueError):
66            self.account.deposit(0.0)
67    
68    def test_withdraw(self):
69        self.account.withdraw(30.0)
70        self.assertAlmostEqual(self.account.get_balance(), 70.0, places=2)
71    
72    def test_withdraw_more_than_balance(self):
73        with self.assertRaises(ValueError):
74            self.account.withdraw(150.0)  # More than the $100 balance
75    
76    def test_withdraw_negative_amount(self):
77        with self.assertRaises(ValueError):
78            self.account.withdraw(-10.0)
79    
80    def test_close_account(self):
81        self.account.close_account()
82        self.assertFalse(self.account.is_account_active())
83    
84    def test_deposit_on_closed_account(self):
85        self.account.close_account()
86        with self.assertRaises(RuntimeError):
87            self.account.deposit(10.0)
88    
89    def test_withdraw_from_closed_account(self):
90        self.account.close_account()
91        with self.assertRaises(RuntimeError):
92            self.account.withdraw(10.0)
93
94if __name__ == '__main__':
95    unittest.main()

Example 3: Testing a Shopping Cart

  1# shopping_cart.py
  2class ShoppingCart:
  3    def __init__(self, tax_rate):
  4        self.items = []
  5        self.prices = {}
  6        self.tax_rate = tax_rate
  7    
  8    def add_item(self, item, price):
  9        if not item or not item.strip():
 10            raise ValueError("Item name cannot be empty")
 11        if price < 0:
 12            raise ValueError("Price cannot be negative")
 13        self.items.append(item)
 14        self.prices[item] = price
 15    
 16    def remove_item(self, item):
 17        if item not in self.items:
 18            raise ValueError("Item not in cart")
 19        self.items.remove(item)
 20        del self.prices[item]
 21    
 22    def get_subtotal(self):
 23        return sum(self.prices.values())
 24    
 25    def get_tax(self):
 26        return self.get_subtotal() * self.tax_rate
 27    
 28    def get_total(self):
 29        return self.get_subtotal() + self.get_tax()
 30    
 31    def get_item_count(self):
 32        return len(self.items)
 33    
 34    def is_empty(self):
 35        return len(self.items) == 0
 36
 37# test_shopping_cart.py
 38import unittest
 39from shopping_cart import ShoppingCart
 40
 41class TestShoppingCart(unittest.TestCase):
 42    TAX_RATE = 0.08  # 8% tax
 43    
 44    def setUp(self):
 45        self.cart = ShoppingCart(self.TAX_RATE)
 46    
 47    def test_empty_cart(self):
 48        self.assertTrue(self.cart.is_empty())
 49        self.assertEqual(self.cart.get_item_count(), 0)
 50        self.assertAlmostEqual(self.cart.get_subtotal(), 0.0, places=2)
 51        self.assertAlmostEqual(self.cart.get_total(), 0.0, places=2)
 52    
 53    def test_add_single_item(self):
 54        self.cart.add_item("Apple", 1.50)
 55        
 56        self.assertFalse(self.cart.is_empty())
 57        self.assertEqual(self.cart.get_item_count(), 1)
 58        self.assertAlmostEqual(self.cart.get_subtotal(), 1.50, places=2)
 59        self.assertAlmostEqual(self.cart.get_tax(), 0.12, places=2)  # 1.50 * 0.08
 60        self.assertAlmostEqual(self.cart.get_total(), 1.62, places=2)  # 1.50 + 0.12
 61    
 62    def test_add_multiple_items(self):
 63        self.cart.add_item("Apple", 1.50)
 64        self.cart.add_item("Banana", 0.75)
 65        self.cart.add_item("Orange", 2.00)
 66        
 67        self.assertEqual(self.cart.get_item_count(), 3)
 68        self.assertAlmostEqual(self.cart.get_subtotal(), 4.25, places=2)  # 1.50 + 0.75 + 2.00
 69        self.assertAlmostEqual(self.cart.get_tax(), 0.34, places=2)       # 4.25 * 0.08
 70        self.assertAlmostEqual(self.cart.get_total(), 4.59, places=2)     # 4.25 + 0.34
 71    
 72    def test_add_item_with_empty_name(self):
 73        with self.assertRaises(ValueError):
 74            self.cart.add_item("", 1.00)
 75    
 76    def test_add_item_with_none_name(self):
 77        with self.assertRaises(ValueError):
 78            self.cart.add_item(None, 1.00)
 79    
 80    def test_add_item_with_negative_price(self):
 81        with self.assertRaises(ValueError):
 82            self.cart.add_item("Apple", -1.00)
 83    
 84    def test_remove_item(self):
 85        self.cart.add_item("Apple", 1.50)
 86        self.cart.add_item("Banana", 0.75)
 87        
 88        self.cart.remove_item("Apple")
 89        
 90        self.assertEqual(self.cart.get_item_count(), 1)
 91        self.assertAlmostEqual(self.cart.get_subtotal(), 0.75, places=2)
 92    
 93    def test_remove_nonexistent_item(self):
 94        self.cart.add_item("Apple", 1.50)
 95        with self.assertRaises(ValueError):
 96            self.cart.remove_item("Orange")  # Orange was never added
 97    
 98    def test_zero_tax_rate(self):
 99        no_tax_cart = ShoppingCart(0.0)
100        no_tax_cart.add_item("Apple", 1.50)
101        
102        self.assertAlmostEqual(no_tax_cart.get_subtotal(), 1.50, places=2)
103        self.assertAlmostEqual(no_tax_cart.get_tax(), 0.0, places=2)
104        self.assertAlmostEqual(no_tax_cart.get_total(), 1.50, places=2)
105
106if __name__ == '__main__':
107    unittest.main()

Running Your Tests

Java (JUnit4)

1# Compile your classes and tests
2javac -cp .:junit-4.12.jar:hamcrest-core-1.3.jar *.java
3
4# Run the tests
5java -cp .:junit-4.12.jar:hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest

Python (unittest)

1# Run a specific test file
2python test_calculator.py
3
4# Run all tests in the current directory
5python -m unittest discover
6
7# Run with more verbose output
8python -m unittest -v test_calculator.py

The Reality Check

When you’re starting out, writing tests feels like:

  1. Extra work - “I already wrote the code, why write more code?”
  2. Slowing you down - “I could build three features in the time it takes to test one”
  3. Pointless - “My code obviously works, I just tested it manually”

But here’s what happens as you grow as a developer:

Week 1: “Tests are stupid, they slow me down”
Month 3: “Okay, tests caught a few bugs, but I still don’t have time”
Year 1: “Holy crap, my tests just saved me from deploying broken code”
Year 2: “I refuse to write code without tests”

The transition happens when you experience your first major bug that tests would have caught, or when you need to refactor a complex piece of code and your tests give you the confidence to do it fearlessly.

Your Testing Journey

Start small:

  1. Write tests for new methods - Don’t retrofit your entire codebase
  2. Test the scary parts - Complex logic, edge cases, anything involving math
  3. Test when you find bugs - Write a test that reproduces the bug, then fix it
  4. Make it a habit - Eventually, you’ll feel uncomfortable shipping untested code

Remember: Good code is tested code. And tested code is code you can trust.

Pro Tip: Name your test methods descriptively. testAdd() is okay, but testAddWithNegativeNumbers() tells you exactly what broke when the test fails at 2 AM.