对于一个简单的Python模块来说,非常常见的目录结构似乎是将单元测试分离到它们自己的测试目录中:
new_project/
antigravity/
antigravity.py
test/
test_antigravity.py
setup.py
etc.
我的问题很简单,实际运行测试的通常方式是什么?我怀疑这对每个人来说都是显而易见的,除了我,但你不能只是从测试目录运行python test_antigravity.py,因为它的导入antigravity将失败,因为模块不在路径上。
我知道我可以修改PYTHONPATH和其他与搜索路径相关的技巧,但我不能相信这是最简单的方法——如果您是开发人员,这很好,但如果用户只是想检查测试是否通过,那么期望他们使用这种方法是不现实的。
另一种替代方法是将测试文件复制到另一个目录中,但这似乎有点愚蠢,并且没有注意到将它们放在一个单独的目录中。
那么,如果您刚刚下载源代码到我的新项目,您将如何运行单元测试?我更喜欢这样的答案:“要运行单元测试,请执行x。”
如果您正在寻找命令行解决方案:
基于以下目录结构(使用专用源目录进行概括):
new_project/
src/
antigravity.py
test/
test_antigravity.py
Windows:(在new_project中)
$ set PYTHONPATH=%PYTHONPATH%;%cd%\src
$ python -m unittest discover -s test
如果您想在批for循环中使用此语句,请参阅此问题。
Linux:(在new_project中)
$ export PYTHONPATH=$PYTHONPATH:$(pwd)/src [I think - please edit this answer if you are a Linux user and you know this]
$ python -m unittest discover -s test
使用这种方法,还可以在必要时向PYTHONPATH添加更多目录。
我也遇到了同样的问题,使用了一个单独的单元测试文件夹。根据上述建议,我将绝对源路径添加到sys.path中。
以下解决方案的好处是,你可以运行test/test_yourmodule.py文件,而不需要一开始就切换到test目录:
import sys, os
testdir = os.path.dirname(__file__)
srcdir = '../antigravity'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))
import antigravity
import unittest
从你链接的文章中:
Create a test_modulename.py file and
put your unittest tests in it. Since
the test modules are in a separate
directory from your code, you may need
to add your module’s parent directory
to your PYTHONPATH in order to run
them:
$ cd /path/to/googlemaps
$ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps
$ python test/test_googlemaps.py
Finally, there is one more popular
unit testing framework for Python
(it’s that important!), nose. nose
helps simplify and extend the builtin
unittest framework (it can, for
example, automagically find your test
code and setup your PYTHONPATH for
you), but it is not included with the
standard Python distribution.
也许你应该像它所暗示的那样看看鼻子?
Python unittest模块的解决方案/示例
鉴于以下项目结构:
ProjectName
├── project_name
| ├── models
| | └── thing_1.py
| └── __main__.py
└── test
├── models
| └── test_thing_1.py
└── __main__.py
你可以使用python project_name从根目录运行你的项目,它调用ProjectName/project_name/__main__.py。
要使用python test运行测试,有效地运行ProjectName/test/__main__.py,您需要执行以下操作:
1)通过添加__init__.py文件将您的test/models目录转换为一个包。这使得子目录中的测试用例可以从父测试目录中访问。
# ProjectName/test/models/__init__.py
from .test_thing_1 import Thing1TestCase
2)在test/__main__.py中修改系统路径以包含project_name目录。
# ProjectName/test/__main__.py
import sys
import unittest
sys.path.append('../project_name')
loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)
现在您可以在测试中成功地从project_name导入内容。
# ProjectName/test/models/test_thing_1.py
import unittest
from project_name.models import Thing1 # this doesn't work without 'sys.path.append' per step 2 above
class Thing1TestCase(unittest.TestCase):
def test_thing_1_init(self):
thing_id = 'ABC'
thing1 = Thing1(thing_id)
self.assertEqual(thing_id, thing.id)
我通常在项目目录中创建一个“运行测试”脚本(对于源目录和测试都是通用的),用于加载我的“所有测试”套件。这通常是样板代码,所以我可以在项目之间重用它。
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
有了这个设置,你确实可以在你的测试模块中包含反重力。缺点是你需要更多的支持代码来执行一个特定的测试…我每次都把它们都运行一遍。