如果您正在编写库或应用程序,则单元测试文件会放在哪里?
将测试文件与主应用程序代码分开是很好的选择,但是将它们放在应用程序根目录内的“ tests”子目录中是很尴尬的,因为这使得导入要测试的模块更加困难。
这里有最佳实践吗?
如果您正在编写库或应用程序,则单元测试文件会放在哪里?
将测试文件与主应用程序代码分开是很好的选择,但是将它们放在应用程序根目录内的“ tests”子目录中是很尴尬的,因为这使得导入要测试的模块更加困难。
这里有最佳实践吗?
Answers:
对于文件module.py
,通常应test_module.py
遵循Pythonic命名约定来调用单元测试。
有几个公认的地方test_module.py
:
module.py
。../tests/test_module.py
(与代码目录处于同一级别)。tests/test_module.py
(代码目录下的一级)。我更喜欢#1,因为它可以轻松找到测试并将其导入。无论您使用哪种构建系统,都可以轻松地将其配置为运行以开头的文件test_
。实际上,用于测试发现的默认unittest
模式是test*.py
。
如果只有1个测试文件,建议将其放在顶层目录中:
module/
lib/
__init__.py
module.py
test.py
在CLI中运行测试
python test.py
如果有许多测试文件,请将其放在tests
文件夹中:
module/
lib/
__init__.py
module.py
tests/
test_module.py
test_module_function.py
# test_module.py
import unittest
from lib import module
class TestModule(unittest.TestCase):
def test_module(self):
pass
if __name__ == '__main__':
unittest.main()
在CLI中运行测试
# In top-level /module/ folder
python -m tests.test_module
python -m tests.test_module_function
unittest discovery
unittest discovery
将在包文件夹中找到所有测试。
创建一个__init__.py
in tests/
文件夹
module/
lib/
__init__.py
module.py
tests/
__init__.py
test_module.py
test_module_function.py
在CLI中运行测试
# In top-level /module/ folder
# -s, --start-directory (default current directory)
# -p, --pattern (default test*.py)
python -m unittest discover
通常的做法是将tests目录放置在与模块/软件包相同的父目录中。因此,如果您的模块名为foo.py,则目录布局将如下所示:
parent_dir/
foo.py
tests/
当然,没有一种方法可以做到这一点。您也可以创建一个tests子目录,然后使用绝对导入来导入模块。
无论您在哪里进行测试,我都建议您使用鼻子进行测试。鼻子会在您的目录中搜索测试。这样,您可以在组织上最有意义的地方进行测试。
编写Pythoscope(https://pypi.org/project/pythoscope/)时,我们遇到了同样的问题,该问题会为Python程序生成单元测试。在选择目录之前,我们对python列表中的测试人员进行了调查,结果有很多不同的见解。最后,我们选择将“ tests”目录放置在与源代码相同的目录中。在该目录中,我们为父目录中的每个模块生成一个测试文件。
正如杰里米·坎特雷尔(Jeremy Cantrell)所述,我也倾向于将单元测试放在文件本身中,尽管我倾向于不将测试功能放在主体中,而是将所有内容放在一个文件中。
if __name__ == '__main__':
do tests...
块。最后,将文档添加到文件中作为“示例代码”,以说明如何使用要测试的python文件。
我应该补充一点,我倾向于编写非常紧凑的模块/类。如果您的模块需要大量测试,则可以将它们放在另一个测试中,但是即使如此,我仍然要添加:
if __name__ == '__main__':
import tests.thisModule
tests.thisModule.runtests
这使任何阅读您的源代码的人都知道在哪里可以找到测试代码。
我偶尔会检查一下测试放置的主题,大多数人每次都在库代码旁边推荐一个单独的文件夹结构,但是我发现每次参数都相同且并不那么令人信服。我最终将测试模块放在核心模块旁边。
这样做的主要原因是:重构。
当我四处移动时,我确实希望测试模块随代码一起移动。如果测试位于单独的树中,则很容易丢失测试。老实说,迟早您会得到一个完全不同的文件夹结构,例如django,flask和许多其他文件夹。如果您不在乎,那很好。
您应该问自己的主要问题是:
我在写:
如果一个:
一个单独的文件夹以及保持其结构的额外工作可能会更适合。没有人会抱怨您的测试被部署到生产环境中。
但是,将测试与核心文件夹混合时,也可以将测试从分发中排除出去,这同样容易。把它放在setup.py中:
find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"])
如果b:
就像我们每个人一样,您可能希望您正在编写可重用的库,但是大多数时候它们的生命与项目的生命息息相关。轻松维护项目的能力应该是首要任务。
然后,如果您做得很好,并且您的模块非常适合另一个项目,则可能会将其复制(而不是分叉或制作成单独的库)复制到此新项目中,并将位于其旁边的测试移动到同一文件夹结构中与在一个单独的测试文件夹变得混乱的情况下进行测试相比,这很容易。(您可能会争辩说,一开始它不应该是一团糟,但让我们在这里变得现实)。
因此,选择仍然是您的选择,但我认为,通过混合测试,您可以实现与使用单独的文件夹相同的所有功能,但是可以使工作保持整洁。
我认为没有公认的“最佳实践”。
我将测试放在应用程序代码之外的另一个目录中。然后,在运行所有测试之前,在测试运行器脚本(还执行其他一些操作)中,将主应用程序目录添加到sys.path中(允许您从任何位置导入模块)。这样,我发布时就不必从主代码中删除测试目录,从而节省了时间和精力。
os.sys.path.append(os.dirname('..'))
根据我在Python中开发测试框架的经验,我建议将python单元测试放在单独的目录中。保持对称目录结构。这将有助于仅打包核心库而不打包单元测试。下面是通过示意图实现的。
<Main Package>
/ \
/ \
lib tests
/ \
[module1.py, module2.py, [ut_module1.py, ut_module2.py,
module3.py module4.py, ut_module3.py, ut_module.py]
__init__.py]
这样,当您使用rpm打包这些库时,您可以仅打包主库模块(仅)。这有助于维护性,尤其是在敏捷环境中。
我建议您检查GitHub上的一些主要Python项目并获得一些想法。
当代码变大并添加更多库时,最好在具有setup.py的目录中创建一个测试文件夹,并为每种测试类型(unittest,integration等)镜像项目目录结构。
例如,如果您具有如下目录结构:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
setup.py
添加测试文件夹后,您将具有以下目录结构:
myPackage/
myapp/
moduleA/
__init__.py
module_A.py
moduleB/
__init__.py
module_B.py
test/
unit/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
integration/
myapp/
moduleA/
module_A_test.py
moduleB/
module_B_test.py
setup.py
许多正确编写的Python软件包都使用相同的结构。Boto软件包就是一个很好的例子。检查https://github.com/boto/boto
matplotlib
在matplotlib/lib/matplotlib/tests
(github.com/matplotlib/matplotlib/tree/…)sklearn
下有它,在scikitelearn/sklearn/tests
(github.com/scikit-learn/scikit-learn/tree/master/sklearn/tests)下有它
我该怎么做...
资料夹结构:
project/
src/
code.py
tests/
setup.py
Setup.py指向src /作为包含我的项目模块的位置,然后运行:
setup.py develop
它将我的项目添加到站点程序包中,指向我的工作副本。要运行测试,我使用:
setup.py tests
使用我配置的任何测试运行程序。
code.py
。将顶层目录称为“项目”会更有意义。
我更喜欢顶级测试目录。这确实意味着进口变得更加困难。为此,我有两个解决方案:
test_suite='tests.runalltests.suite'
进入setup()
,并可以简单地运行测试:python setup.py test
PYTHONPATH=. python tests/runalltests.py
M2Crypto中的代码如何支持这些东西:
如果您希望通过鼻子测试运行测试,则可能需要做一些不同的事情。
如果测试很简单,只需将它们放在docstring中-大多数适用于Python的测试框架都可以使用:
>>> import module
>>> module.method('test')
'testresult'
对于其他涉及更多的测试,我会将它们放在../tests/test_module.py
或中tests/test_module.py
。
在编写名为“ foo”的程序包时,我会将单元测试放入单独的程序包“ foo_test”中。这样,模块和子软件包将与SUT软件包模块具有相同的名称。例如,在foo_test.xy中找到模块foo.xy的测试。然后,每个测试包的__init__.py文件都包含一个AllTests套件,其中包括该包的所有测试套件。setuptools提供了一种方便的方法来指定主要的测试包,以便在“ python setup.py development”之后,您可以仅对“ python setup.py test”或“ python setup.py test -s foo_test.x.SomeTestSuite”使用只是一个特定的套件。
我将测试与被测代码(CUT)放在同一目录中。用于foo.py
测试将在foo_ut.py
或相似。(我调整了测试发现过程以找到这些。)
这会将测试放在目录列表中的代码旁边,从而使测试很明显,并且使测试在单独文件中时的打开变得尽可能容易。(对于命令行编辑器,vim foo*
以及在使用图形文件系统浏览器时,只需单击CUT文件,然后单击紧邻的测试文件。)
正如其他人指出的那样,如果需要的话,这也使得重构和提取代码以在其他地方使用变得更加容易。
我真的不喜欢将测试放在完全不同的目录树中的想法;为什么在使用CUT打开文件时,使开发人员更难以打开测试?并不是说绝大多数开发人员都热衷于编写或调整测试,以至于他们会忽略这样做的任何障碍,而不是以障碍为借口。(根据我的经验,情况恰恰相反;即使您使它尽可能地容易,我也知道许多开发人员不会为编写测试而烦恼。)