Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 36 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
36
Dung lượng
163,86 KB
Nội dung
Chapter 16 Functional Programming 16.1 Diving in In Chapter 13, Unit Testing, you learned about the philosophy of unit testing In Chapter 14, Test-First Programming, you stepped through the implementation of basic unit tests in Python In Chapter 15, Refactoring, you saw how unit testing makes large-scale refactoring easier This chapter will build on those sample programs, but here we will focus more on advanced Python-specific techniques, rather than on unit testing itself The following is a complete Python program that acts as a cheap and simple regression testing framework It takes unit tests that you've written for individual modules, collects them all into one big test suite, and runs them all at once I actually use this script as part of the build process for this book; I have unit tests for several of the example programs (not just the roman.py module featured in Chapter 13, Unit Testing), and the first thing my automated build script does is run this program to make sure all my examples still work If this regression test fails, the build immediately stops I don't want to release non-working examples any more than you want to download them and sit around scratching your head and yelling at your monitor and wondering why they don't work Example 16.1 regression.py If you have not already done so, you can download this and other examples used in this book """Regression testing framework This module will search for scripts in the same directory named XYZtest.py Each such script should be a test suite that tests a module through PyUnit (As of Python 2.1, PyUnit is included in the standard library as "unittest".) This script will aggregate all found test suites into one big test suite and run them all at once """ import sys, os, re, unittest def regressionTest(): path = os.path.abspath(os.path.dirname(sys.argv[0])) files = os.listdir(path) test = re.compile("test\.py$", re.IGNORECASE) files = filter(test.search, files) filenameToModuleName = lambda f: os.path.splitext(f)[0] moduleNames = map(filenameToModuleName, files) modules = map( import , moduleNames) load = unittest.defaultTestLoader.loadTestsFromModule return unittest.TestSuite(map(load, modules)) if name == " main ": unittest.main(defaultTest="regressionTest") Running this script in the same directory as the rest of the example scripts that come with this book will find all the unit tests, named moduletest.py, run them as a single test, and pass or fail them all at once Example 16.2 Sample output of regression.py [you@localhost py]$ python regression.py -v help should fail with no object ok help should return known result for apihelper ok help should honor collapse argument ok help should honor spacing argument ok buildConnectionString should fail with list input ok buildConnectionString should fail with string input ok buildConnectionString should fail with tuple input ok buildConnectionString handles empty dictionary ok buildConnectionString returns known result with known input ok fromRoman should only accept uppercase input ok toRoman should always return uppercase ok fromRoman should fail with blank string ok fromRoman should fail with malformed antecedents ok fromRoman should fail with repeated pairs of numerals ok fromRoman should fail with too many repeated numerals ok fromRoman should give known result with known input ok toRoman should give known result with known input ok fromRoman(toRoman(n))==n for all n ok toRoman should fail with non-integer input ok toRoman should fail with negative input ok toRoman should fail with large input ok toRoman should fail with input ok kgp a ref test ok kgp b ref test ok kgp c ref test ok kgp d ref test ok kgp e ref test ok kgp f ref test ok kgp g ref test ok -Ran 29 tests in 2.799s OK The first tests are from apihelpertest.py, which tests the example script from Chapter 4, The Power Of Introspection The next tests are from odbchelpertest.py, which tests the example script from Chapter 2, Your First Python Program The rest are from romantest.py, which you studied in depth in Chapter 13, Unit Testing 16.2 Finding the path When running Python scripts from the command line, it is sometimes useful to know where the currently running script is located on disk This is one of those obscure little tricks that is virtually impossible to figure out on your own, but simple to remember once you see it The key to it is sys.argv As you saw in Chapter 9, XML Processing, this is a list that holds the list of command-line arguments However, it also holds the name of the running script, exactly as it was called from the command line, and this is enough information to determine its location Example 16.3 fullpath.py If you have not already done so, you can download this and other examples used in this book import sys, os print 'sys.argv[0] =', sys.argv[0] pathname = os.path.dirname(sys.argv[0]) print 'path =', pathname print 'full path =', os.path.abspath(pathname) Regardless of how you run a script, sys.argv[0] will always contain the name of the script, exactly as it appears on the command line This may or may not include any path information, as you'll see shortly os.path.dirname takes a filename as a string and returns the directory path portion If the given filename does not include any path information, os.path.dirname returns an empty string os.path.abspath is the key here It takes a pathname, which can be partial or even blank, and returns a fully qualified pathname os.path.abspath deserves further explanation It is very flexible; it can take any kind of pathname Example 16.4 Further explanation of os.path.abspath >>> import os >>> os.getcwd() /home/you >>> os.path.abspath('') /home/you >>> os.path.abspath('.ssh') /home/you/.ssh >>> os.path.abspath('/home/you/.ssh') /home/you/.ssh >>> os.path.abspath('.ssh/ /foo/') /home/you/foo os.getcwd() returns the current working directory Calling os.path.abspath with an empty string returns the current working directory, same as os.getcwd() Calling os.path.abspath with a partial pathname constructs a fully qualified pathname out of it, based on the current working directory Calling os.path.abspath with a full pathname simply returns it os.path.abspath also normalizes the pathname it returns Note that this example worked even though I don't actually have a 'foo' directory os.path.abspath never checks your actual disk; this is all just string manipulation Note The pathnames and filenames you pass to os.path.abspath not need to exist Note os.path.abspath not only constructs full path names, it also normalizes them That means that if you are in the /usr/ directory, os.path.abspath('bin/ /local/bin') will return /usr/local/bin It normalizes the path by making it as simple as possible If you just want to normalize a pathname like this without turning it into a full pathname, use os.path.normpath instead Example 16.5 Sample output from fullpath.py [you@localhost py]$ python /home/you/diveintopython/common/py/fullpath.py sys.argv[0] = /home/you/diveintopython/common/py/fullpath.py path = /home/you/diveintopython/common/py full path = /home/you/diveintopython/common/py [you@localhost diveintopython]$ python common/py/fullpath.py sys.argv[0] = common/py/fullpath.py path = common/py full path = /home/you/diveintopython/common/py [you@localhost diveintopython]$ cd common/py [you@localhost py]$ python fullpath.py sys.argv[0] = fullpath.py path = full path = /home/you/diveintopython/common/py In the first case, sys.argv[0] includes the full path of the script You can then use the os.path.dirname function to strip off the script name and ... sys.argv[0] = /home/you/diveintopython/common/py/fullpath.py path = /home/you/diveintopython/common/py full path = /home/you/diveintopython/common/py [you@localhost diveintopython]$ python common/py/fullpath.py... = /home/you/diveintopython/common/py [you@localhost diveintopython]$ cd common/py [you@localhost py]$ python fullpath.py sys.argv[0] = fullpath.py path = full path = /home/you/diveintopython/common/py... like this without turning it into a full pathname, use os.path.normpath instead Example 16.5 Sample output from fullpath.py [you@localhost py]$ python /home/you/diveintopython/common/py/fullpath.py