# CS 410 Python Testing & Debugging Guide # Understanding the Problem First, you should understand both what the code currently does, and what the code should be doing. The best way to do this is with a specific example - think of an example test, where there is an exact input and an expected output. Seeing the ways in which your program’s output differs from the expected one, with the same input, is an important first step to understanding and rectifying the problems in your code. # Reading Error Messages A few common error messages and what they mean: - **Null pointer exception**: a variable is not initialized before being referenced (for example, updating a counter by adding one to itself without setting it to 0 beforehand) - **Out of bounds error**: occurs when trying to access a position that is ‘out of bounds’ in a data structure (for example, referencing an index in an array that is greater than its length) # Identifying Error-Producing Regions of the Code Sometimes, you aren’t getting any error messages, but you know something is wrong anyway since your program isn’t outputting the right thing. Here, it’s helpful to manually figure out which region of the code is buggy by following the steps below. The best types of examples to work with are complex enough that you are testing at least some features of the program (e.g. not an empty list), but not too complex that they are needlessly difficult to work out the output by hand. Often the output/error message will point to the section of the code that is producing errors, but if not, tracing through each step of your code and tracking values of variables or other intermediate structures and identifying where those values differ from the expected value stored can help you zero in on your bug. If the program is producing the expected output on some inputs but not others, writing a wide range of tests (and covering edge cases!) can be useful to identify patterns where the program fails. In addition, test cases that isolate and verify that individual functions perform correctly can break up the hand-tracing into smaller parts. # Using Print Statements Print statements can also help with programs that get longer and when there are too many intermediate values to store in your head. You might want to print relevant variable values at a certain point/in a certain function, and better understand where and why your code is going wrong. # Setting Breakpoints Setting breakpoints is one of the most efficient ways of stepping through your code and understanding how it executes, especially when you're working with complex logic or can't easily trace values manually. In VSCode, setting breakpoints allows you to pause the program at a specific line of code, allowing you to inspect variables, the call stack, and more. By using breakpoints effectively, you can trace issues step by step and quickly resolve bugs. ### Steps to Set Breakpoints in VSCode for Python 2. On the left gutter (the area to the left of the line numbers), click next to the line number where you want to set a breakpoint. A red dot will appear to indicate the breakpoint has been set. 3. Start debugging by selecting `Run` > `Start Debugging` from the top menu, or simply press `F5`. 4. VSCode will execute the program and pause execution when it hits the breakpoint. 5. Once paused, you can inspect the variables panel on the left to view the current state of variables, or hover over variables in the editor to see their values. 6. You can then use the debugging controls (Continue, Step Over, Step Into, Step Out) to navigate through the code line by line and understand the program’s behavior. - **Step Over** (`F10`): Executes the current line and moves to the next line, skipping over function calls. - **Step Into** (`F11`): Steps into any function calls on the current line, allowing you to debug the function in more detail. - **Step Out** (`Shift + F11`): If you're inside a function, this will execute the rest of the function and return to the calling function. - **Continue** (`F5`): Resumes execution until the next breakpoint is hit (if any). ### Helpful Tips for Debugging in VSCode - **Conditional Breakpoints**: Right-click on a breakpoint and choose "Edit Breakpoint" to add a condition, such as stopping only when a variable reaches a specific value. - **Watch Variables**: You can add variables to the "Watch" section in the debugging sidebar to track how their values change as you step through the code. - **Call Stack**: Use the call stack to trace back to the sequence of function calls that led to the current breakpoint. This is particularly helpful for understanding how control flows through the program. - **Debug Console**: Use the Debug Console to interactively run Python commands while your program is paused. This allows you to test assumptions or manually inspect variables. # Debugging Tips - Use descriptive variable names! This can go a long way to helping you understand, especially in longer code. - Don’t make assumptions, especially about the validity of a function/part of your code. - Look at both syntax and logic - a bug can be a logical flaw in your function, but it can also be something you overlook, like a semicolon. - Take a break! Coming back to the code with fresh eyes does wonders with helping you figure out what’s wrong :)