Exercises for Lesson 14

Back to Lesson 14

Exercise 1: Input validation

Up until now, we’ve assumed that users provide the type of input we want. Add error checking to the following function. In your modified version, the program should just return from main early if the user types anything 2 or smaller for n.

from graphics import *

def main():
    # Get the number of points from the user
    n = int(input("How many points would you like? "))

    # Make the window
    win = GraphWin("A shape with " + str(n) + " points", 800, 600)

    # Get the points
    points = []
    for i in range(n):
        p = win.getMouse()
        points.append(p)
        p.draw(win)

    # Draw the polygon
    polygon = Polygon(points)
    polygon.setFill("forest green")
    polygon.draw(win)

main()

Back to Lesson 14

Exercise 2: A simple unit test

We can use the unittest Python module to test our code. For example, consider the following function:

def doStuff(x, y):
    if x < y:
        return 7
    else:
        return x-y

Part a: happy path

The “happy path” for this function is testing the usual code paths when things go well. What should the return values be for doStuff(4, 10) and doStuff(20, 10)?

Here is a simple Python program that will test these happy path cases, with two lines for you to fill in:

import unittest

def doStuff(x, y):
    if x < y:
        return 7
    else:
        return x-y

class Test_Happy(unittest.TestCase):

    def testIf(self):
        expected = # TODO: what number do we expect in this case?
        actual = doStuff(4, 10)
        self.assertEqual(expected, actual)

    def testElse(self):
        expected = # TODO: what number do we expect in this case?
        actual = doStuff(20, 10)
        self.assertEqual(expected, actual)

if __name__ == "__main__":
    unittest.main(verbosity=2)

Fill in the values to make the tests pass.

Part b: edge cases

We should also check for edge cases (also known as boundary conditions). For this program, that would be when we’re on the border of the if condition. For example, what if x and y are equal? Add a test case for this:

class Test_Edge(unittest.TestCase):

    def testInputsEqual(self):
        # TODO: add code to test for this case
        pass # replace with your code

Part c: invalid cases

Realistically, we shouldn’t trust our users. We should also check for really unexpected inputs. For this function, that may be values that aren’t numbers. Maybe we really just want ints and floats.

Write some test cases with inputs that aren’t numbers.

Part d: test-driven development

The tests you wrote for Part c should fail. Add some error handling to doStuff to handle this. Hint: the function isinstance(obj, types) takes in a variable and a type (or tuple of types). For example:

x = 4
y = 2.3
z = [x, y]
isinstance(x, int) # True
isinstance(x, float) # False
isinstance(x, (int, float)) # True
isinstance(y, (int, float)) # True
isinstance(z, (int, float)) # False

With your changes to doStuff, your tests from Part c should now pass.

Back to Lesson 14