6.00.1x Week 4

Our code does not always work as we intended, so we need to have some ways to debug it.

Testing and debugging

Testing methods
Ways to test the program with examples to see if it work as intended.
Debugging methods
Ways to fix the program after you know it does not work as intended.

Testing methods

Our goal in testing is to reveal bugs in our program. This means finding inputs that does not give an intended result when fed into a program. One of the ways to find a bug is to test all inputs, but there may be infinitely many possible inputs into our program, so, how do we test each input?

We partition all possible test cases/ input (space) into groups of similar test cases (subset) where each test case in the group will give a similar result if fed into the program. Then we pick a test case from each subset and test it. These picked test cases will be our test suite.

Test cases partition
Test cases partition

For example, to test a function isBigger():

The input space is all pairs of integers, the partition can be as follows, we pick one test case from each partition and form our test suite:

  • x: positive, y: positive
  • x: negative, y: negative
  • x: positive, y: negative
  • x: negative, y: positive
  • x = 0, y = 0
  • x = 0, y != 0
  • x != 0, y = 0

For programs that don’t have natural partition to input spaces, we can use:

  1. Random testing
    • Randomly selects input to test. The probability that the code is correct increases when more input is tested.
  2. Black-box testing
    • Test cases are chosen based on specification of the program. Specification is what it promised to do or what is its functionality.
    • These test cases can be chosen by people other than the coder.
    • Moreover, if the implementation code is different, it still uses same test cases, because it focuses on the specification/ functionality.
    • How to implement? Follow the path through the specification, that is each step of what the specification says, choose test cases to test that.
  3. Glass-box testing
    • Test cases are chosen based on the internal structure of the program, i.e. the code, instead of functionality.
    • How to implement? Follow path through the code.

Debugging methods

Now that we have found, via testing methods, that our programs has bug(s), we can start to debug them.

The first
“Moth found trapped between points at Relay # 70, Panel F, of the Mark II Aiken Relay Calculator while it was being tested at Harvard University, 9 September 1947.” The First “Computer Bug” by Naval Surface Warfare Center, Dahlgren, VA., 1988

Types of bug

  1. Overt vs. covert (Is the bug significant?)
    • Overt – has obvious manifestation. E.g. Program crashes or run forever.
    • Covert – no obvious manifestation. E.g. Returns a value, but the value may be incorrect.
  2. Persistent vs. intermittent (Does the bug occurs frequently?)
    • Persistent – Occurs every time program is run.
    • Intermittent – Only occurs some time, even if the input is same.

Debugging is like a search problem, we are searching for code that creates the bug. First, we test our test cases, when a bug occurs with one of the test cases, we start to investigate.

We will use print to expose the intermediate stages of computation. Where should we put the print statement? By following the concept of binary search, we put the print statement at the middle of our code. Then, run the code. If the print statement displays something that is not what intended it to display, then we know the bug must be somewhere in the top half of the code, else, the bug is in the bottom half of the code. If the bug is in the top half, we would like to put another print statement in the middle of the top half, then test again, if the middle of the top half still gives unintended result, we repeating the process of eliminating half of the codes searching for bug in the top half of the top half.

When we finally fix a bug, there may be another bug somewhere else. Do similar search for bugs until there is no bug left.

Computer always execute codes correctly as what we typed, instead of asking why the code is not doing what it should be, we should ask, why the code is doing what it is doing.

Exceptions and Assertions

Exceptions

Our code may runs correctly, it outputs correct output given input(s), however, once in a while, we may input input(s) that will cause exception (unexpected condition). We know we cause an exception if the program terminates and the python interpreter gives an error, we say this exception is unhandled because the program terminates. We have ways to handle exceptions ourselves.

Types of exception that can be raised:

  • IndexError – Trying to access values in list that is beyond the index limit. E.g. Test = [1, 2, 3], Test[4]
  • TypeError – Use wrong data type. E.g. ‘a’ / 4, Int(Test)
  • ValueError – Correct data type but value is illegal.
  • NameError – Referencing a non-existing variable.
  • SyntaxError – Python cannot parse the program.
  • AttributeError – attribute reference fails.
  • IOError – Input/ Output system malfunction. E.g. file not found
  • ZeroDivisionError – Divide by zero.

Python provides handlers for exceptions. The syntax is as follows:

Exception(s) occurred in the try body is handled by the except statement, then execution continues. In this case, when the user inputs y as zero, a zero division exception occurs, x / y will not be assigned to result, execution will pass to ZeroDivisionError except statement to handle the exception, printing out “Division by zero!”. Then execution continue after the try and except block.

Handlers are used to deal with specific exception, in this case ZeroDivisionError. We can put many except statements to handle different type of exceptions as follows:

Besides except statement, there are some extension to the try statement. We can also use else and finally.

else – body of this is executed if the try body finished execution with no error.

finally – body of this is executed even if there is an exception. This block is put after try, except and else.

Example:

If we divide(7, 0), it will raise a zero division exception, and is handled by that ZeroDivisionError except statement, printing “division by zero!” and the error object, e. Error object contains the name of the function causing the error and some description like line number. Since it raised an error, the else statement will not execute. Lastly, the finally statement is executed, printing “executing finally clause”.

Assertions

We use assertion to give an assumption.  If the assumption is violated, then it will return an assertion error.

For example:

The function Normalize takes a list as an input, it stored the biggest number of the list in max_number, then loop over each number of the list and divide them by max_number. Lastly, it returns the list.

The function has two assertion, first, the max_number cannot be a 0, because later we will divide the list element by max_number. Second, the value of element in list number after division, cannot be less than 0 or more than 1, because smaller number or max_number itself divide by max_number must get values from 0 to 1. If the first assertion fails, it will print “Cannot divide by 0”, if the second assertion fails, it will print “output not between 0 and 1”.

Assertion can be used on input (pre condition), or output (post condition).

Problem set 4

In this problem set, we have to code a word game that is similar to Scrabble. User will get some letters that are randomized, and user has to use the letters to form word(s), only words found in dictionary are allowed, in this case we uses words.txt. The score is calculated by summing the score of the words. The score of a word is calculated by summing the points of the letters, the letter’s point is A for 1, B for 2, and so on, then multiplying it with the length of the word. If the word formed uses all the letters, an extra 50 points is given.

Second version of the game allows user to have a choice to let computer play the game for the user. The computer will search the words.txt and find a word that gives the most point.

My codes: https://github.com/shaunlgs/MITx-6.00.1x-OCW-2014

Leave a Reply