Read the text and answer the questions

Have you ever tried to drive in a nail with a screwdriver or dig a hole with a hammer? If so, you were probably frustrated because you didn't have the right tool for the job. Finding errors in your code is no different! If you don't have the right tools or skills, identifying coding problems can be difficult.

Now, if you have a syntax error, Python will tell you about it with a specific error message. So, syntax errors are usually not too hard to figure out. In this lesson, we are going to focus on runtime errors instead, which are often harder to identify and fix. Fortunately, software engineers have at least three common tools they can use to help spot and fix runtime errors. Your coding experience will become easier as your gain confidence with these tools.

Tool #1 - Code Review
If something goes wrong in your Python program, you can simply look at the code and try to figure out the error. This is called a code review or hand tracing. A good set of human eyes can be great troubleshooters! For small programs with just a few lines of code, you may not need a formal code review strategy. However, as your programs become more complex, you will want to follow a specific code review process to have the best chance of finding the problem.

Remember that Python will run your program from top to bottom, one line at a time. The computer doesn't know about statements it hasn't reached yet, and each line of code can only work based on statements that have already been run. So, to perform a complete code review, follow these steps:

Begin with an understanding of the run-time error you are trying to fix. If the output is incorrect, or you get an exception message, those are important clues that will help guide your code review.
Examine the first statement and answer the following questions:
Do you understand what the statement is supposed to do?
Are you confident the statement is correctly written to do what you want?
Is the statement formatted correctly and is easy to read?
What are the expected results from this statement?
Do any nearby comments match what the statement actually does?
What variables or data does this statement use?
Is there any way that variable data could be incorrect or contain unexpected values?
Is there any way this statement could produce the runtime error that you observed?
If you are calling a Python function, look at the Python reference material at to make sure you understand how to use that function.
What are the function parameters?
What does the function do?
What data does the function return, if any?
Once you are confident in the current statement, move to the next one and repeat the inspection process.
Repeat your careful review of each statement until you find the one that causes the runtime error.
Remember, each statement will run based on the variables and logic that have been initialized and run by earlier statements. Python can't look ahead to see what you intended later!
When a programmer leaves comments in a program, they are often important clues that can help you follow the logic and understand what is supposed to happen. But keep in mind that comments themselves can be wrong or misleading!

Look at the code below. This program demonstrates a math party trick that you can use on your friends. It asks the user for a secret integer, then leads the user through a series of calculations. The actual calculations are made by the program as well, and the result is displayed at each step. The final answer should always be 5, no matter what original value was entered. The program will double-check the math and print a confirmation message if correct, or an error message if the result does not equal 5.The example below shows the correct output if the user enters 12 as a secret integer.

Enter a secret positive integer: 12
Now, double that number. We calculate: 24
Then, add 10 to the result. We calculate: 34
Then, divide the result by 2. We calculate: 17.0
Finally, subtract your original number. We calculate: 5.0
The final answer is always 5
Sometimes you can greatly speed up a code review by focusing on a particular area of code. Perhaps you have 100 statements in your program and you feel confident the first 75 worked fine based on the output you saw. In that case, start your code review later in the program with the statements that seem the most suspicious.

Tool #2 - Program Tracing
If you are unable to find a problem with a code review, you can consider adding program tracing instead. Tracing is a useful tool that displays temporary, extra output messages as the program runs. These extra output messages are not intended for a regular user but will give you, the programmer, some understanding of what the program is doing as the code runs.

Remember the print() function is used to display text to the screen. So, you can use the print() function to add program traces at key points in your program. You may want to add a print() statement each time an "if", "elif" or "else" block of logic is run. You might also add trace statements to display the contents of key variables as they are updated.

Consider the following code, which is supposed to calculate the bill at a restaurant, including a tip for the server. With a base price of $10.00, a tax rate of 7%, and a tip of $2.00, we would expect the final bill to be $12.70. Notice how good code comments give you some clues as to what the statements should be doing!

price = 10.00
taxRate = 0.07
tax = price * taxRate # calculate the tax
total = taxRate + tax # add the tax to the price
tip = 2.00
if (tip < 0): # if there is a tip
total = total + tip # add the tip to the bill
print("Your total bill is: $",total)
Copy
However, the actual output total is only $0.77, not $12.70. While you might be able to spot the errors with a code review, let's add some program tracing to help you understand what the program is doing. The updated example below contains some extra print() statements to trace key bits of information to the screen as the program runs. Try it and see!With the extra trace statements, you should see the following output:

Calculated tax = $ 0.7000000000000001
Calculated total = $ 0.77
Tip = $ 2.0
Your total bill is: $ 0.77
Right away you can see that the first calculated total is incorrect. Adding the tax ($0.70) to the price ($10.00) should give you $10.70. Therefore, we know there is something fishy about the first total assignment statement. Go ahead and fix that statement so it correctly adds the price and the tax and run the program again. You should see some new output.

Calculated tax = $ 0.7000000000000001
Calculated total = $ 10.7
Tip = $ 2.0
Your total bill is: $ 10.7
Now, the first calculated total is correct ($10.70). However, our print() statement that says "adding tip to total..." is not visible in the output! This means our "if" logical expression is not True. We are expecting that expression to be True when the tip is greater than 0. Go ahead and fix that logical expression and run the program again. You should now get the expected output, $12.70, as shown below.

Calculated tax = $ 0.7000000000000001
Calculated total = $ 10.7
Tip = $ 2.0
adding tip to total...
Your total bill is: $ 12.7
Don't forget, when you have fixed all your errors, you will want to remove the temporary trace statements. They just clutter up the output and are not supposed to be seen by a regular user. You can delete the extra print() lines or just comment them out if you think they might become useful again later.Sometimes, code reviews or program tracing just isn't enough. To understand and fix a problem, you really need to watch the program as it executes, step-by-step. A debugger is a software tool that provides this capability! When running a program in a debugger, you can study the result of the last statement and look ahead to the next statement. You can even peek at the values inside your variables to make sure everything looks the way you expect. Python contains a debugger that is easy to use. You'll learn all about the Python debugger in the next lesson.As you troubleshoot a problem with a code review, program tracing, or a debugger, you will need to clearly understand the program requirements. Your program requirements will define the allowable types of input data and specify what output data should be produced for each input. With this information, you can create a series of test cases. A test case defines a specific set of inputs and the expected program output. You may need to run or review code many times to check all of your test cases and ensure the program works under all conditions.

If your program logic is hard to understand, a visualization may help. Diagrams of program behavior (such as a flowchart) can help illustrate what should happen at each step of the logic, given specific inputs. These visualizations can be easier to follow than lines of code. You'll learn how to create flowcharts to represent program logic later in the course!





Testing Boundary Conditions and Handling Invalid Data
Programmers will commonly write code that works well with expected data. But what happens if your program tries to process some invalid values? If you ask users to enter a number like "3", they might type in "three" instead. Or a user might click on a "Submit" button while leaving some required list entries or checkboxes de-selected. You should expect users to enter all kinds of invalid data - anything your program allows them to do, even incorrectly, will eventually happen over time!

Therefore, well-written programs should carefully check all input data before using it. Verify that you have everything you need in the correct format before continuing. If there is a problem with the data, display a message to the user so the problem can be fixed. When testing your program, make sure to not only test with valid data, but with all possible kinds of invalid input as well!

Similarly, the user may enter valid data that is just rare. For example, if you ask a user for their age, you might expect a 2-digit number between 0 and 99. But someone may realistically enter a 3-digit number such as 101. Or, you might write a program to keep track of all the individual parts that make up a machine. The program might work well with 10, 20, or even 100 parts. But what happens if someone tries to define a machine with 10,000 or even a million different parts? Your program may crash or become so slow that it can't be used.

These unusual (but valid) numbers represent boundary conditions. Programmers should carefully define the range of data expected for all values and understand how to handle data that is unusual in any way. As a tester, it's your job to explore these boundary conditions with test cases and ensure they are handled gracefully by the program. So, when asked for a number, try entering very large, very small, and negative numbers. Or, if you are entering text, you might try entering empty, very short, and very long strings to see what happens.

Programmers should spend time verifying and handling invalid inputs and boundary conditions. That way programs will not encounter costly problems once given to users.

Testing With Authentic Data
Another useful approach to program verification is to use real data gathered from reliable sources. For example, if your program is supposed to calculate statistics for a sports team, you can visit that team's website to gather raw data. Or, if your program will convert temperatures between Celsius and Fahrenheit systems, you can gather real data from public weather websites to double-check your output. You may find new boundary conditions in real data that you didn't consider when creating test data by hand!

1. What are three common tools that software engineers can use to help spot and fix runtime errors?

- Code review
- Program tracing
- Debugger

2. What is the purpose of a code review?
The purpose of a code review is to examine the code and identify any errors or issues that may be causing runtime errors. It involves carefully reviewing each statement and checking for correctness, clarity, and alignment with the intended purpose of the code. It can also involve reviewing comments and ensuring they accurately reflect the code's functionality.

3. How can program tracing be helpful in identifying and fixing errors?
Program tracing involves adding temporary print statements at key points in the code to display information about the program as it runs. These extra output messages can help the programmer understand what the program is doing and identify any unexpected values or errors. By tracing the program's execution, the programmer can gain insight into the flow of the program and pinpoint the source of any runtime errors.

4. What is the purpose of a debugger?
A debugger is a software tool that allows programmers to step through their code and observe its execution, line by line. It provides the ability to stop the program at specific points, examine variable values, and understand how the program is behaving. Debuggers are particularly useful for identifying and fixing runtime errors by allowing the programmer to closely analyze the state of the program at various stages of execution.

5. Why is it important to test a program with both valid and invalid data?
Testing a program with both valid and invalid data is important because it helps ensure that the program can handle various scenarios and inputs correctly. Valid data testing checks if the program produces the expected output for correctly formatted input. Invalid data testing checks if the program handles and responds appropriately to invalid or unexpected input, such as incorrect data types, out-of-range values, or missing information. By testing with both types of data, programmers can identify and address any issues or errors related to data processing and validation.

Read the text and answer the following questions

1. What information should you gather before starting a code review?
2. What are some common questions you would ask as you examine each statement in a code review?
3. Do comments provide useful information when conducting a code review?
4. Do you always need to start a code review at the beginning? Why or why not?
5. What Python statement do you add to insert program traces in your code?
6. What kind of information might you display in trace statements?
7. Are trace statements intended for the programmer or the end user? Do you leave trace statements in your code when done?
8. What kind of software tool will let you examine a program and variable contents as the program runs, step-by-step?

1. Before starting a code review, you should gather an understanding of the runtime error you are trying to fix, including any error messages or incorrect output you have observed. You should also review the code and have a clear understanding of the intended purpose of each statement and any relevant function documentation or references.

2. Some common questions you would ask as you examine each statement in a code review include:
- Do you understand what the statement is supposed to do?
- Is the statement correctly written to achieve its intended purpose?
- Is the statement formatted correctly and easy to read?
- What are the expected results from this statement?
- Do any nearby comments match the actual behavior of the statement?
- What variables or data does this statement use? Are they properly initialized and can they contain unexpected values?
- Is there any possibility of the statement causing the observed runtime error?

3. Yes, comments can provide useful information during a code review. They can help explain the purpose or behavior of certain parts of the code, provide context, or highlight any known issues or limitations. However, it's important to remember that comments themselves can be incorrect or misleading, so they should be reviewed critically.

4. No, you don't always need to start a code review at the beginning. If you have identified or suspect that the error is located in a specific area or set of statements, you can start the code review there to focus your efforts on the suspicious code. This can save time, especially in larger programs.

5. The print() statement is used to insert program traces in Python code. By using the print() function, you can display temporary output messages at key points in the program to understand its behavior.

6. In trace statements, you might display information such as the values of variables, the results of calculations, the execution of conditional statements (if, elif, else), or any other relevant information that helps track the flow of the program and identify issues.

7. Trace statements are intended for the programmer, not the end user. They provide additional insight into the program's execution and are used for debugging purposes. When done with the code review or debugging process, it is recommended to remove or comment out the trace statements as they are not meant to be part of the final code.

8. The kind of software tool that allows you to examine a program and variable contents as the program runs, step-by-step, is called a debugger. Python has a built-in debugger that can be used to study the execution of the code, inspect variable values, and understand the program's behavior at different stages of execution.