Exercises for 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()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-yPart 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 codePart 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)) # FalseWith your changes to doStuff, your tests from Part c should now pass.