Week 13: Unit testing and Object-Oriented design
Lectures:
You must be logged on to your swarthmore.edu account for the youtube lecture videos to be viewable. |
Unit testing
It is crucial that your programs behave as you intend them to. Unit testing is a method of building tests right into the program itself. Every time you make a change to the program the unit tests will ensure that you haven’t broken something in the code.
In Python, we can use assert
to implement unit tests. An assertion
is an expression that you expect to evaluate to True
. If it is true,
as expected, then nothing happens. However, if it is not true, then an
assertion error will be raised. Consider the following class
definition and accompanying main
program that uses assert
to create
a set of unit tests.
class Team(object):
def __init__(self, name, sport):
self.name = name
self.sport = sport
self.wins = 0
self.losses = 0
def __str__(self):
return "Team:%s Wins:%d Losses:%d" % \
(self.name, self.wins, self.losses)
def getName(self):
return self.name
def getWins(self):
return self.wins
def getLosses(self):
return self.losses
def wonGame(self):
self.wins += 1
def lostGame(self):
self.losses += 1
def main():
print("Unit testing the Team class...")
t = Team("SwatCS", "ICPC")
assert(t.getWins() == 0)
assert(t.getLosses() == 0)
assert(t.getName() == "SwatCS")
t.wonGame()
t.wonGame()
t.lostGame()
assert(t.getWins() == 2)
assert(t.getLosses() == 1)
print(t)
print("Team class passed all unit tests!")
if __name__ == '__main__':
main()
The special if
statement at the bottom of the program will only
execute the main
program when you run this file directly like this:
python3 team.py
. If instead you import
this file, the main
program will not be executed. This is one way to build unit testing
right into the program itself.
Here’s the output you would see from running this program:
Unit testing the Team class...
Team:SwatCS Wins:2 Losses:1
Team class passed all unit tests!
Suppose we had a mistake in our implementation. For example, perhaps
in creating the lostGame()
method we accidentally decremented
self.wins
instead of incrementing self.losses
. Now when we run
this program we would see the following output:
Unit testing the Team class...
Traceback (most recent call last):
File "team.py", line 36, in <module>
main()
File "team.py", line 30, in main
assert(t.getWins() == 2)
AssertionError
The AssertionError
will interrupt the program execution immediately,
and indicate the line number where the problem occurred.
Object-Oriented Design
Now that you understand the syntax and semantics of creating your own classes in Python we can think more broadly about the process of object-oriented design.
A common rule of thumb in object-oriented design is that for each individual type of object in the real world your program should have a corresponding class defined. One way to go about the design process is to write down a description of your problem. The nouns in that description will likely correspond with the classes you’ll need and the verbs in that description will likely correspond with methods you’ll need.
Let’s create the infrastructure we need to implement a card game such as Blackjack.
Card games typically use a deck of 52 cards. Each card has one of 4 suits (clubs, diamonds, hearts, or spades) and one of 13 ranks (ace, 2, 3, …, 10, jack, queen, or king). Most games start by shuffling the deck and then deal out hands to each player.
Based on this description, we should create classes for Card, Deck, and Hand. We should also have methods for dealing and shuffling.
Do an update21
to get all of the files you’ll need to play
Blackjack. Start by adding unit tests into the file cards.py
that
contains class definitions for both Card
and Deck
.