即使是一个简单的 Python 模块,最常见的目录结构似乎也是将单元测试分成各自的test
目录:
new_project/
antigravity/
antigravity.py
test/
test_antigravity.py
setup.py
etc.
例如,参见此Python 项目 howto 。
我的问题是,实际上运行测试的通常方法是什么?我怀疑这对除我以外的所有人来说都是显而易见的,但您不能仅从python test_antigravity.py
,因为其import antigravity
将失败,因为模块不在路径上。
我知道我可以修改 PYTHONPATH 和其他与搜索路径有关的技巧,但是我不敢相信这是最简单的方法 - 如果您是开发人员,那很好,但如果用户只是想检查测试结果,就不能期望用户使用通过。
另一种选择是将测试文件复制到另一个目录中,但似乎有点愚蠢,并且错过了将它们放在一个单独目录中的意义。
那么,如果您刚刚将源代码下载到我的新项目中,将如何运行单元测试?我希望有一个答案让我对用户说:“要运行单元测试,请执行 X。”
我认为最好的解决方案是使用unittest
命令行界面,该界面会将目录添加到sys.path
因此您不必(在TestLoader
类中完成)。
例如,对于这样的目录结构:
new_project
├── antigravity.py
└── test_antigravity.py
您可以运行:
$ cd new_project
$ python -m unittest test_antigravity
对于像您这样的目录结构:
new_project
├── antigravity
│ ├── __init__.py # make it a package
│ └── antigravity.py
└── test
├── __init__.py # also make test a package
└── test_antigravity.py
test
包内部的测试模块中,您可以antigravity
包及其模块:
# import the package
import antigravity
# import the antigravity module
from antigravity import antigravity
# or an object inside the antigravity module
from antigravity.antigravity import my_object
运行一个测试模块:
要运行单个测试模块,在这种情况下为test_antigravity.py
:
$ cd new_project
$ python -m unittest test.test_antigravity
只需以导入模块的相同方式引用测试模块即可。
运行单个测试用例或测试方法:
您也可以运行一个TestCase
或一个测试方法:
$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method
运行所有测试:
您还可以使用测试发现来为您发现并运行所有测试,它们必须是名为test*.py
模块或软件包(可以通过-p, --pattern
标志进行更改):
$ cd new_project
$ python -m unittest discover
$ # Also works without discover for Python 3
$ # as suggested by @Burrito in the comments
$ python -m unittest
这将运行test
包中的test*.py
模块。
对用户来说,最简单的解决方案是提供一个可执行脚本( runtests.py
或类似的脚本),该脚本引导必要的测试环境,包括在需要时将根项目目录临时sys.path
这不需要用户设置环境变量,类似这样的东西在引导脚本中可以很好地工作:
import sys, os
sys.path.insert(0, os.path.dirname(__file__))
然后,您对用户的说明就可以像 “ python runtests.py
” 一样简单。
当然,如果您真正需要的路径是os.path.dirname(__file__)
,则根本不需要将其添加到sys.path
中。 Python 始终将当前正在运行的脚本的目录放在sys.path
的开头,因此根据您的目录结构,仅需要将runtests.py
定位在正确的位置即可。
另外, Python 2.7 + 中的 unittest 模块(已反向移植为 Python 2.6 及更早版本的unittest2 )现在具有内置的测试发现功能,因此,如果您要进行自动测试发现,则不再需要鼻子:您的用户说明可以很简单python -m unittest discover
。
我通常在项目目录(源目录和test
共同的目录)中创建一个 “运行测试” 脚本,以加载我的 “所有测试” 套件。这通常是样板代码,因此我可以在项目之间重复使用它。
run_tests.py:
import unittest
import test.all_tests
testSuite = test.all_tests.create_test_suite()
text_runner = unittest.TextTestRunner().run(testSuite)
test / all_tests.py(来自我如何在目录中运行所有 Python 单元测试? )
import glob
import unittest
def create_test_suite():
test_file_strings = glob.glob('test/test_*.py')
module_strings = ['test.'+str[5:len(str)-3] for str in test_file_strings]
suites = [unittest.defaultTestLoader.loadTestsFromName(name) \
for name in module_strings]
testSuite = unittest.TestSuite(suites)
return testSuite
通过此设置,您确实可以仅在测试模块中include antigravity
不利的一面是您需要更多的支持代码来执行特定的测试…… 我每次都运行它们。