General Beginner

Debugging and Testing: Finding and Fixing Problems

CodingerWeb
CodingerWeb
22 views 35 min read

Debugging: The Detective Work of Programming

Debugging is the process of finding and fixing errors (bugs) in your code. Every programmer spends time debugging - it's a normal and important part of programming!

What are Bugs?

Bugs are errors in your code that cause it to behave differently than expected. The term "bug" comes from an actual moth found in an early computer in 1947!

Types of Bugs

1. Syntax Errors

Mistakes in the code structure - like typos or missing punctuation.

Syntax Error Examples

// Missing closing parenthesis
    print("Hello World"  ❌
    print("Hello World") ✅
    
    // Misspelled keyword
    funciton greet():    ❌
    function greet():    ✅
    
    // Missing quotes
    name = Alice         ❌
    name = "Alice"       ✅

2. Logic Errors

Code runs but produces wrong results because the logic is incorrect.

Logic Error Example

// Wrong: This calculates area incorrectly
    function calculateRectangleArea(length, width):
        return length + width  ❌ (should be multiplication)
        
    // Correct version
    function calculateRectangleArea(length, width):
        return length * width  ✅

3. Runtime Errors

Errors that occur while the program is running, often due to unexpected conditions.

Runtime Error Examples

// Division by zero
    result = 10 / 0  ❌ (causes runtime error)
    
    // Accessing array out of bounds
    numbers = [1, 2, 3]
    print(numbers[5])  ❌ (index 5 doesn't exist)
    
    // Better approach with checking
    if index < length(numbers):
        print(numbers[index])  ✅
    else:
        print("Index out of range")

Debugging Strategies

1. Read Error Messages Carefully

Error messages often tell you exactly what's wrong and where.

Understanding Error Messages

Error: NameError: name 'userName' is not defined
    Line 15: print(userName)
    
    // This tells us:
    // - Type: NameError (variable doesn't exist)
    // - Problem: 'userName' is not defined
    // - Location: Line 15
    // - Solution: Define userName or check spelling

2. Use Print Statements

Add print statements to see what's happening in your code.

Debugging with Print Statements

function calculateGrade(score, total):
        print("DEBUG: score = " + score)        // Check input
        print("DEBUG: total = " + total)        // Check input
        
        percentage = score / total * 100
        print("DEBUG: percentage = " + percentage)  // Check calculation
        
        if percentage >= 90:
            grade = "A"
        else if percentage >= 80:
            grade = "B"
        else:
            grade = "C"
            
        print("DEBUG: final grade = " + grade)  // Check result
        return grade

3. Rubber Duck Debugging

Explain your code line by line to a rubber duck (or any object). Often, you'll spot the problem while explaining!

4. Check Your Assumptions

Verify that your inputs and variables contain what you think they do.

Checking Assumptions

function processUserInput(input):
        // Assumption: input is a number
        // Let's verify this assumption
        print("Input received: '" + input + "'")
        print("Input type: " + typeof(input))
        
        if typeof(input) != "number":
            print("ERROR: Expected number, got " + typeof(input))
            return null
            
        // Now we can safely use input as a number
        return input * 2

Testing Your Code

Why Test?

  • Catch bugs before users do
  • Ensure code works as expected
  • Make sure changes don't break existing functionality
  • Build confidence in your code

Types of Testing

1. Manual Testing

Run your program and try different inputs to see if it works correctly.

Manual Testing Checklist

// Testing a login function
    Test Cases:
    1. Valid username and password ✓
    2. Valid username, wrong password ✓
    3. Invalid username ✓
    4. Empty username ✓
    5. Empty password ✓
    6. Very long username ✓
    7. Special characters in password ✓
2. Automated Testing

Write code that tests your code automatically.

Simple Automated Test

// Function to test
    function add(a, b):
        return a + b
        
    // Test function
    function testAdd():
        // Test case 1: positive numbers
        result1 = add(2, 3)
        if result1 == 5:
            print("✓ Test 1 passed")
        else:
            print("✗ Test 1 failed: expected 5, got " + result1)
            
        // Test case 2: negative numbers
        result2 = add(-1, -2)
        if result2 == -3:
            print("✓ Test 2 passed")
        else:
            print("✗ Test 2 failed: expected -3, got " + result2)
            
        // Test case 3: zero
        result3 = add(0, 5)
        if result3 == 5:
            print("✓ Test 3 passed")
        else:
            print("✗ Test 3 failed: expected 5, got " + result3)
            
    // Run tests
    testAdd()

Common Debugging Techniques

1. Binary Search Debugging

If you have a large program with a bug, comment out half the code to narrow down where the problem is.

2. Start Simple

Test with the simplest possible inputs first, then gradually increase complexity.

3. Check Edge Cases

Test unusual or extreme inputs:

  • Empty inputs
  • Very large numbers
  • Negative numbers
  • Special characters

Edge Case Testing

function divide(a, b):
        // Edge case: division by zero
        if b == 0:
            return "Error: Cannot divide by zero"
            
        return a / b
        
    // Test edge cases
    print(divide(10, 2))    // Normal case: 5
    print(divide(10, 0))    // Edge case: Error message
    print(divide(0, 5))     // Edge case: 0
    print(divide(-10, 2))   // Edge case: -5

Debugging Tools

1. Debugger

Most programming environments have debuggers that let you:

  • Step through code line by line
  • Set breakpoints to pause execution
  • Inspect variable values
  • Watch how variables change

2. Logging

Instead of print statements, use proper logging:

Logging Example

function processOrder(order):
        log.info("Processing order: " + order.id)
        
        if order.items.length == 0:
            log.warning("Order " + order.id + " has no items")
            return false
            
        total = calculateTotal(order.items)
        log.info("Order total: $" + total)
        
        if total > 1000:
            log.warning("Large order detected: $" + total)
            
        return true

🎯 Debugging Practice

Find and fix the bugs in these code snippets:

// Bug 1: Find the syntax error
    function greetUser(name {
        return "Hello, " + name + "!"
    }
    
    // Bug 2: Find the logic error
    function isEven(number):
        if number % 2 == 1:
            return true
        else:
            return false
            
    // Bug 3: Find the potential runtime error
    function getFirstItem(list):
        return list[0]

Best Practices for Bug Prevention

  • Write clear, readable code - easier to spot mistakes
  • Use meaningful variable names - reduces confusion
  • Test frequently - catch bugs early
  • Handle edge cases - prevent runtime errors
  • Add comments - explain complex logic
  • Keep functions small - easier to debug

When You're Stuck

  • Take a break - fresh eyes often spot problems
  • Ask for help - explain the problem to someone else
  • Search online - others have likely faced similar issues
  • Read documentation - make sure you're using functions correctly
  • Start over - sometimes rewriting is faster than debugging