Lab 9 - While loops and unit testing

Part 1: While loops

If you are not sure what’s going on with while-loops, see Eels, Chapter 17.

Checkpoint 1

  1. With pencil and paper, trace execution of the call mystery(3) for the code below. Make a table showing the values of c and n at the end of the loop body and determine the value returned.
def mystery(n):
    c = 0
    while n != 1:
        c += 1
        if n % 2 == 0:
            n = n // 2
        else:
            n = n * 3 + 1
    return c
  1. Rewrite the code below so that it uses a while-loop instead of a for-loop.
  1. Rewrite the code below so that it uses a for-loop instead of a while-loop.

Part 2: Using a while-loop

Checkpoint 2

  1. Here’s a typical scenario: Say you have $10000 saved up and you’re going off to travel the world. You plan to take out a stipend of $400 a month to live on, and you keep the rest of the money in a mutual fund that earns 6% per year (i.e., half a percent per month). How long would it be until you run out of money? (As a warm-up, how much do you have after two months? You take out $400, leaving $9600. A month goes by, so the account now has 9600 + (9600 * .005) = 9648. You take out another $400, then a month goes by and the account now has 9648 + (9648 * .005) = 9696.24. And so on.)

Write a function

def how_long(given_amount, stipend, rate)

that answers this question in general for any amount, monthly stipend, and interest rate.

  1. Suppose you perform an experiment in which you repeatedly roll a pair of dice, stopping when you roll 12. As you go, you count how many rolls it takes. Write a function that performs this experiment and returns the count. Remember that to simulate rolling two dice, you can do something like
import random

def roll():
    first = random.randrange(1, 7)
    second = random.randrange(1, 7)
    return first + second

Part 3: Unit testing

In order to write code without bugs, we have to first be aware of what the errors are. Typically we rely on testing to reveal the presence of errors. A unit test is a test that focuses on checking the correctness of one specific function or module. A unit test consists of a set of test cases, which are usually just calls to the function with a known result that can be checked.

For this exercise, we are providing you with several different implementations of one function. One of the implementations is correct and the rest contain errors. The function is called longest_run. Given a string, it returns the longest “run” of consecutive matching characters. For example, given the string “aabbbabbab”, it should return “bbb”. If there are multiple runs of the same length, it should return the first such run.

Your task is to come up with a set of test cases for this function. Your goal is to come up with enough test cases to identify the bugs in the incorrect versions. That is,

  1. For the correct implementation of the function, all your test cases pass, AND
  2. For an incorrect implementation of the function, at least one of your test cases will fail

Think about what kinds of things are likely to go wrong, and test for them. E.g., loops often have off-by-one errors. So what happens if the longest run is right at the beginning or end of the string?

The sample implementations are in different modules longest.py, longest2.py, longest3.py, etc. Write your test code in the file longest_test.py. You can use the same code to test a different implementation just by changing the import statement at the top of the file. The correct one is longest.py.

In previous examples, we have written test cases that just print out the function’s value. We can then look at the output on the screen and evaluate whether it’s correct. When there are a lot of test cases, that’s a lot of work. For this example, we’ll use a “helper function” that checks the function result against the known correct answer, and only prints a message if the result is wrong. (This is also the strategy you’ll use in Homework 4.) The helper function is simple - you just pass in the string you want to call the longest_run function with, and you pass in the correct result.

def test_longest_run(arg, expected):
    '''
    Checks result for longest_run
    '''
    actual = longest_run(arg) # call the function with the given string arg
    if expected != actual:    # compare the result to the expected answer
        print("ERROR: longest_run(" + str(arg) + ")")
        print("Expected:", expected, "Actual:", actual)

Note that for this exercise we are encouraging you to do “black-box” style testing, where you try to come up with test cases based on the specification, without actually seeing the source code that you are testing. (Of course, you can look at the source code, but you’ll find that it has been deliberately obfuscated and is extremely difficult to read!)

Each test case should start with a comment stating what it is you are trying to test. See the example in longest_test.py. You can see more examples in the file mayan_test.py that is part of the Homework 4 sample code.

You can find the sample code in the directory:

http://web.cs.iastate.edu/~smkautz/cs127f16/labs/lab9_sample_code/

or download a zip file with all 7 modules:

http://web.cs.iastate.edu/~smkautz/cs127f16/labs/lab9_sample_code/lab9_sample_code.zip

Checkpoint 3

Show the TA your set of test cases. Demonstrate items 1 and 2 above.