Announcements CSE 399-004: Python Programming Lecture 07: Packages, Command-line arguments, and Unit testing February 26, 2007 http://www.seas.upenn.edu/~cse39904/ No homework this week There may be one or two more homeworks later If so, they will be short Projects Should have received feedback on your proposal Might be a good idea to start on them now Some of you were asked to send me email I'll ask later in the term if I should change the due date No office hours during Spring Break I'll be in town though Send email if you want to meet 2 Today Packages Command-line arguments Unit testing: The unittest module Packages (Tutorial, Section 6.4) 3 Packages: Overview A package collects together many modules and organizes them into some hierarchy Packages: Concretely A package in Python is simply any directory that contains a file named The organization of files (modules) on disk determines the structure of the hierarchy Useful since putting many modules in the same directory can be cumbersome Aside: Packages in Python are similar to packages in Java 5 A sample package hierarchy. 6
Packages: Concretely A package in Python is simply any directory that contains a file named Packages: Concretely A package in Python is simply any directory that contains a file named Unlike in Java, nothing special is needed within these files to make them part of a package. A subpackage of the Sound package. 6 6 Importing from packages import Sound.Effects.echo from Sound.Effects import echo Importing from packages import Sound.Effects.echo from Sound.Effects import echo Only the "dot-notation" is new here. 7 7 Imports within packages Imports across package boundaries need to use the full package names Imports within packages Imports across package boundaries need to use the full package names import surround import Sound.Formats.wavread 8 8
Imports within packages Imports across package boundaries need to use the full package names import surround from..formats import wavread Python also supports relative imports, but I think it's clearer to write out paths in full. 9 Command-line arguments Why command-line arguments? Even in this age of graphical user interfaces (GUIs), it is still common to invoke programs using a command-line It's not nice to pester the user with lots of questions as to what the program should do For example, the Unix cp program has something like 10 20 different options to control its behavior What are command-line arguments? % cse39904submit -a hw5 html/index.html Command-line arguments are an easy way for a user to signal to a program what they want it to do 11 12 What are command-line arguments? What are command-line arguments? program name % cse39904submit -a hw5 html/index.html % cse39904submit -a hw5 html/index.html 12 Three arguments: (1) -a (2) hw5 (3) html/index.html 12
What are command-line arguments? % cse39904submit -a hw5 html/index.html sys.argv The sys module has a variable argv which is a list of the command-line arguments given to the current program Each argument is always a string The first argument is always the name of the program (e.g., file) being run Arguments of the form "-foo" are sometimes referred to as "options" or "flags". 13 14 sys.argv: Example foo.py #!/usr/bin/env python import sys print sys.argv sys.argv: Example The "program name" is useful only your program depends on "how it was called" or if you need to generate something like a usage message. %./foo.py arg1 200 arg3 ['./foo.py', 'arg1', '200', 'arg3'] % python foo.py a b 30 ['foo.py', 'a', 'b', '30'] % python foo.py ['foo.py'] %./foo.py arg1 200 arg3 ['./foo.py', 'arg1', '200', 'arg3'] % python foo.py a b 30 ['foo.py', 'a', 'b', '30'] % python foo.py ['foo.py'] 15 15 The optparse module Parsing "interesting" command-line arguments by hand is painful and error prone except The optparse module provides an easy way for you to specify flags/options and then parse them 16 17
Automatically knows that -h means to print out a help message. Does not know about any other flags. Tells the parser to look for the -a flag. 17 17 Actually parse sys.argv. Information about flags passed in is stored in options, and args will be a list of all other command-line arguments. 18 % cse39904submit! options.assn == None! args == [ ] 19 % cse39904submit -a hw1! options.assn == 'hw1'! args == [ ] 20 % cse39904submit -a hw1 file1 file2! options.assn == 'hw1'! args == [ 'file1', 'file2'] 21
References There are many things you can do with OptParsers http://docs.python.org/lib/module-optparse.html % cse39904submit file1 -a hw1 file2! options.assn == 'hw1'! args == [ 'file1', 'file2'] 22 23 What is unit testing? Unit testing: Overview Well-written programs can be broken up into "units" Individual functions and methods Classes Modules Packages Unit testing aims to test the functionality of all the "units" in your program 25 Why unit testing? Testing whole programs is difficult Too many code paths to verify Too many behaviors to check for Isolating bugs is tricky It makes more sense to test things by checking the smaller units first, then the larger ones This naturally isolates bugs and problematic behavior Test cases themselves can serve as documentation, e.g., examples of (in)correct behavior Regression testing Programs evolve over time New features are added Bugs are uncovered, then fixed New code can be incorrect or break existing code Makes similar mistakes as previously written code Breaks long held assumptions Regression testing involves the periodic running of test cases to monitor code for the reemergence of bugs Easy to do with a suite of unit tests 26 27
Problems with unit testing Many pieces of code cannot run in complete isolation They may rely on external resources They may rely on other code behaving correctly Two techniques to get around this: Test harnesses: Create a suitable environment before running certain test cases Mock objects: When testing, say, one class, create dummy instances of other necessary classes Goal here: To test one piece of code without relying on other pieces to behave correctly Caveats about testing in general You need to know what your code is supposed to do before you can write test cases for it But, you can still write the test cases for a given piece of code before you write the code itself Beware of bugs in the test cases themselves The test cases are, after all, simply more code Be very careful when using your program's output to write test cases you don't want to use buggy output! 28 29 References http://en.wikipedia.org/wiki/unit_testing http://en.wikipedia.org/wiki/regression_testing Unit testing: The unittest module 30 The unittest module: Overview The unittest module makes it relatively easy to write a suite of unit tests for your programs It is modeled after JUnit, a Java unit testing framework Aside: There are many ways to use unittest I'll describe one way of organizing test cases The module provides other ways Goal for today: Basic introduction to unittest import random import unittest def setup(self): self.seq = range(10) <methods for test cases elided here> if name == ' main ': unittest.main() 32 33
import random import unittest import random import unittest No need to define a constructor. def setup(self): self.seq = range(10) <methods for test cases elided here> if name == ' main ': unittest.main() def setup(self): self.seq = range(10) <methods for test cases elided here> if name == ' main ': unittest.main() The class representing a test case. Can be used to defined multiple cases at once. 33 34 import random import unittest def setup(self): self.seq = range(10) <methods for test cases elided here> if name == ' main ': unittest.main() import random import unittest def setup(self): self.seq = range(10) <methods for test cases elided here> if name == ' main ': unittest.main() The setup() method is called before each test case in this class is run. A similar method teardown() is called Runs the test cases defined in this module. after each test case is run, no matter the result. 34 35 36 Any method whose name starts with "test" defines a test case. These methods should take no arguments. 36
setup() is called before each method is called, The TestCase class provides several methods which test cases should use to test whether certain conditions hold. so these self.seq's will all be equal to range(10). 37 38 TestCase.assertEqual() : Used to test if two values are equal. 39 TestCase.assert_() : Used to test if something is true. 40 Failures versus errors unittest distinguishes "failures" from "errors" Failure: The test case was expecting one thing to happen, and instead something else happen These happen when some assert*() method fails to detect the expected condition or event TestCase.assertRaises() : Test if some exception is thrown. 41 These correspond to incorrect answers Error: An unexpected exception is thrown Corresponds to code doing something incorrect 42
More unittest terminology Test fixture: The framework needed to run a single test case; managed by the TestCase class Test case: Smallest unit of testing; managed by TestCase Test suite: A collection of test cases and test suites Test suites can be built up from other suites Test runner: Component which actually runs test cases and test suites References http://docs.python.org/lib/module-unittest.html In particular, see the TestCase class for all the various assert* and fail* methods that test cases can use 43 44 Final remarks Next class is Monday, March 12, 2007 Do try to enjoy Spring Break List of (potential) future topics: Graphical user interfaces (GUIs) Regular expressions Networking Functional programming [next time?] [near end?] Some of you may have to figure out the above topics before I get a chance to say anything about them 45