16.7. 全部放在一起

你已经学习了足够的知识,现在来分析本章样例代码的前七行:读取一个目录并从中导入选定的模块。

例 16.16. regressionTest 函数


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))          

让我们一行行交互地看。假定当前目录是 c:\diveintopython\py,其中有包含本章脚本在内的本书众多样例。正如在 第 16.2 节 “找到路径” 中所见,脚本目录将存于 path 变量,因此让我们从这里开始以实打实的代码起步。

例 16.17. 步骤 1:获得所有文件

>>> import sys, os, re, unittest
>>> path = r'c:\diveintopython\py'
>>> files = os.listdir(path)                               
>>> files 
['BaseHTMLProcessor.py', 'LICENSE.txt', 'apihelper.py', 'apihelpertest.py',
'argecho.py', 'autosize.py', 'builddialectexamples.py', 'dialect.py',
'fileinfo.py', 'fullpath.py', 'kgptest.py', 'makerealworddoc.py',
'odbchelper.py', 'odbchelpertest.py', 'parsephone.py', 'piglatin.py',
'plural.py', 'pluraltest.py', 'pyfontify.py', 'regression.py', 'roman.py', 'romantest.py',
'uncurly.py', 'unicode2koi8r.py', 'urllister.py', 'kgp', 'plural', 'roman',
'colorize.py']
files 是由脚本所在目录的所有文件和目录构成的列表。(如果你已经运行了其中的一些样例,可能还会看到一些 .pyc 文件。)

例 16.18. 步骤 2:找到你关注的多个文件

>>> test = re.compile("test\.py$", re.IGNORECASE)           
>>> files = filter(test.search, files)                      
>>> files                                                   
['apihelpertest.py', 'kgptest.py', 'odbchelpertest.py', 'pluraltest.py', 'romantest.py']
这个正则表达式将匹配以 test.py 结尾的任意字符串。注意,你必须转义这个点号,因为正则表达式中的点号通常意味着 “匹配任意单字符”,但是你实际上想匹配的事一个真正的点号。
被编译的正则表达式就像一个函数,因此你可以用它来过滤文件和目录构成的大列表,找寻符合正则表达式的所有元素。
剩下的是一个单元测试脚本列表,时时彩计划软件公式:因为只有它们是形如 SOMETHINGtest.py 的文件。

例 16.19. 步骤 3:映射文件名到模块名

>>> filenameToModuleName = lambda f: os.path.splitext(f)[0] 
>>> filenameToModuleName('romantest.py')                    
'romantest'
>>> filenameToModuleName('odchelpertest.py')
'odbchelpertest'
>>> moduleNames = map(filenameToModuleName, files)          
>>> moduleNames                                             
['apihelpertest', 'kgptest', 'odbchelpertest', 'pluraltest', 'romantest']
正如你在 第 4.7 节 “使用 lambda 函数” 中所见,lambda 快餐式地创建内联单行函数。这里应用你在 例 6.17 “分割路径名” 中已经见过的,标准库的 os.path.splitext 将一个带有扩展名的文件名返回成只包含文件名称的那部分。
filenameToModuleName 是一个函数。lambda 函数并不比你以 def 语句定义的普通函数神奇。你可以如其他函数一样地调用 filenameToModuleName,它也将如你所愿:从参数中剔除扩展名。
现在你可以通过 map 把这个函数应用于单元测试文件列表中的每一个文件。
结果当然如你所愿:以指代模块的字符串构成的一个列表。

例 16.20. 步骤 4:映射模块名到模块

>>> modules = map(__import__, moduleNames)                  
>>> modules                                                 
[<module 'apihelpertest' from 'apihelpertest.py'>,
<module 'kgptest' from 'kgptest.py'>,
<module 'odbchelpertest' from 'odbchelpertest.py'>,
<module 'pluraltest' from 'pluraltest.py'>,
<module 'romantest' from 'romantest.py'>]
>>> modules[-1]                                             
<module 'romantest' from 'romantest.py'>
正如你在 第 16.6 节 “动态导入模块” 中所见,你可以通过 map__import__ 的协同工作,将模块名 (字符串) 映射到实际的模块 (像其他模块一样可以被调用和使用)。
modules 现在是一个模块列表,其中的模块和其他模块一样。
该列表的最后一个模块 romantest 模块,和通过 import romantest 导入的模块完全等价。

例 16.21. 步骤 5:将模块载入测试套件

>>> load = unittest.defaultTestLoader.loadTestsFromModule  
>>> map(load, modules)                     
[<unittest.TestSuite tests=[
  <unittest.TestSuite tests=[<apihelpertest.BadInput testMethod=testNoObject>]>,
  <unittest.TestSuite tests=[<apihelpertest.KnownValues testMethod=testApiHelper>]>,
  <unittest.TestSuite tests=[
    <apihelpertest.ParamChecks testMethod=testCollapse>, 
    <apihelpertest.ParamChecks testMethod=testSpacing>]>, 
    ...
  ]
]
>>> unittest.TestSuite(map(load, modules)) 
模块对象的存在,使你不但可以像其他模块一样地使用它们;通过类的实例化和函数的调用,你还可以内省模块,从而弄清楚已经有了那些类和函数。这正是 loadTestsFromModule 方法的工作:内省每一个模块并为每个模块返回一个 unittest.TestSuite 对象。每个 TestSuite (测试套件) 对象都包含一个 TestCase 对象的列表,每个对象对应着你的模块中的一个测试方法。
最后,你将TestSuite列表封装成一个更大的测试套件。unittest 模块会很自如地遍历嵌套于测试套件中的树状结构,最后深入到独立测试方法,一个个加以运行并判断通过或是失败。

自省过程是 unittest 模块经常为我们做的一项工作。还记得我们的独立测试模块仅仅调用了看似神奇的 unittest.main() 函数就大刀阔斧地完成了全部工作吗?unittest.main() 实际上创建了一个 unittest.TestProgram 的实例,而这个实例实际上创建了一个 unittest.defaultTestLoader 的实例并以调用它的模块启动它。 (如果你不给出,如何知道调用它的模块是哪一个?通过使用同样神奇的 __import__('__main__') 命令,动态导入正在运行的模块。我可以就 unittest 模块中使用的所有技巧和技术写一本书,但那样我就没法写完这本了。)

例 16.22. 步骤 6:告知 unittest 使用你的测试套件


if __name__ == "__main__":                   
    unittest.main(defaultTest="regressionTest") 
在不使用 unittest 模块来为我们做这一切的神奇工作的情况下,你实际上已自己做到了。你已经创建了一个自己就能导入模块、调用 unittest.defaultTestLoader 并封装于一个测试套件的 regressionTest 函数。现在你所要做的不是去寻找测试并以通用的方法构建一个测试套件,而是告诉 unittest 前面那些,它将调用 regressionTest 函数,而它会返回可以直接使用的 TestSuite
时时彩软件客户端 w彩票平台 澳门时时彩线上投注 蓝天时时彩信誉平台 优游时时彩平台网址
时时彩被黑报案有用么 时时彩开奖走势图 重庆时时彩网易走势图 福建时时彩软件 香港时时彩软件免费版
精准时时彩软件下载 时时彩平台一条龙 紫光g550高拍仪软件 重庆时时彩资讯刷钱 重庆新时时彩杀号定胆
时时彩可以作为职业吗 吉林11选5基本走势图 江西时时彩推荐 如意时时彩源码分享 世爵娱乐平台官网