Pythonunit testing去了哪里?

如果你正在编写一个库或一个应用程序,unit testing文件在哪里?

将testing文件与主应用程序代码分开是很好的做法,但将它们放到应用程序根目录内的“tests”子目录中是很尴尬的,因为这会导致您将要testing的模块更难导入。

这里有最佳做法吗?

对于一个文件module.py ,unit testing通常被称为test_module.py ,遵循Pythonic命名约定。

有几个普遍接受的地方把test_module.py

  1. 在与module.py相同的目录中。
  2. ../tests/test_module.py (与代码目录在同一级别)。
  3. tests/test_module.py (代码目录下的一个级别)。

我更喜欢#1,因为它简单的findtesting并导入它们。 无论您使用的是哪种构build系统,都可以轻松configuration为以test_开始运行文件。 实际上, 用于testing发现的默认unit testing模式是test*.py

通常的做法是将testing目录放在与您的模块/软件包相同的父目录中。 所以如果你的模块叫做foo.py,你的目录布局看起来像这样:

 parent_dir/ foo.py tests/ 

当然没有办法做到这一点。 您也可以创build一个testing子目录并使用绝对导入导入模块。

无论你把testing放在哪里,我都会build议你用鼻子来运行它们。 鼻子search您的目录进行testing。 这样,你可以把testing放在任何组织最有意义的地方。

只有1个testing文件

如果没有很多testing文件,把它放在顶层目录是好的(我认为这是pythonic(推荐)):

 module/ lib/ __init__.py module.py test.py 

许多testing文件

如果有很多testing文件,把它放在tests文件夹中:

 module/ lib/ __init__.py module.py tests/ test_module.py test_module2.py 

但是如果你把testing放到tests文件夹中,testing不能在CLI中import ..lib ,因为__main__不能导入相关模块,所以我们可以使用nose ,或者我们可以添加一个父目录到Python导入path,为此我将创build一个

env.py

 import sys import os # append module root directory to sys.path sys.path.append( os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) ) ) 

 module/ tests/ test_module.py env.py 

并在testing导入模块之前import env

test_module.py

 import unittest # append parent directory to import path import env # now we can import the lib module from lib import module if __name__ == '__main__': unittest.main() 

编写Pythoscope( http://pythoscope.org )时,我们遇到了同样的问题,Pythoscope为Python程序生成unit testing。 在我们select一个目录之前,我们对python列表中的testing进行了民意调查,结果有很多不同的意见。 最后,我们select将“testing”目录放在与源代码相同的目录中。 在那个目录中,我们为父目录中的每个模块生成一个testing文件。

我也倾向于把我的unit testing放在文件本身,就像上面提到的Jeremy Cantrell所说的那样,尽pipe我倾向于不把testing函数放在主体中,而是把所有东西都放在

 if __name__ == '__main__': do tests... 

块。 这最终将向文件添加文档作为“示例代码”,以了解如何使用正在testing的python文件。

我应该补充一点,我倾向于编写非常紧凑的模块/类。 如果你的模块需要非常大量的testing,你可以把它们放在另一个,但即使如此,我仍然会添加:

 if __name__ == '__main__': import tests.thisModule tests.thisModule.runtests 

这可以让任何人阅读你的源代码知道在哪里寻找testing代码。

我使用tests/目录,然后使用相对导入来导入主应用程序模块。 所以在MyApp / tests / foo.py中,可能有:

 from .. import foo 

导入MyApp.foo模块。

我不相信有一个确定的“最佳实践”。

我把我的testing放在应用程序代码之外的另一个目录中。 然后,在运行所有testing之前,在我的testing运行器脚本(也包括其他一些function)中,将主应用程序目录添加到sys.path(允许您从任何位置导入模块)。 这样,当我释放它时,我永远不必从主代码中移除testing目录,节省了我的时间和精力。

从我在开发Pythontesting框架方面的经验来看,我build议把pythonunit testing放在一个单独的目录中。 维护一个对称的目录结构。 这将有助于打包核心库而不打包unit testing。 下面通过一个示意图来实现。

  <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打包这些库时,可以只包装主库模块(仅)。 这有助于可维护性,特别是在敏捷环境中。

我build议你在GitHub上检查一些主要的Python项目,并得到一些想法。

当你的代码变得更大,并且你添加更多的库时,最好在同一个目录下创build一个testing文件夹,并且为每个testingtypes(unittest,integration,…)镜像你的项目目录结构。

例如,如果你有一个目录结构如:

 myPackage/ myapp/ moduleA/ __init__.py module_A.py moduleB/ __init__.py module_B.py setup.py 

添加testing文件夹后,你将有一个目录结构,如:

 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

我怎么做…

文件夹结构:

 project/ src/ code.py tests/ setup.py 

Setup.py指向src /作为包含我的项目模块的位置,然后我运行:

 setup.py develop 

其中我的项目添加到网站包,指向我的工作副本。 运行我的testing我使用:

 setup.py tests 

使用我configuration的任何一个testing运行器。

每隔一段时间,我都会发现自己检查了testing位置的主题,每次大多数人推荐一个单独的文件夹结构旁边的库代码,但我发现,每次参数是相同的,并没有那么令人信服。 我最终把我的testing模块放在核心模块的旁边。

这样做的主要原因是: 重构

当我移动时,我希望testing模块随代码一起移动; 如果他们在一个单独的树中,很容易失去testing。 说实话,迟早你会得到一个完全不同的文件夹结构,如django , 烧瓶等等。 如果你不在乎,这很好。

你应该问自己的主要问题是:

我在写:

  • a)可重复使用的库或
  • b)build立一个项目,而不是把一些半分离的模块捆绑在一起?

如果一个:

单独的文件夹和维护其结构的额外努力可能更适合。 没有人会抱怨你的testing部署到生产

但是,将testing与核心文件夹混合在一起时,排除testing也同样容易; 把它放在setup.py中 :

 find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"]) 

如果b:

您可能希望 – 像我们每个人一样 – 您正在编写可重用的库,但是大部分时间他们的生活都与项目的生命息息相关。 轻松维护项目的能力应该是重中之重。

那么如果你做得很好,而且你的模块很适合另一个项目,那么它可能会被拷贝到这个新项目中,而不是把它们分支出来或者制作成一个单独的库,很容易相比,在一个单独的testing文件夹已成为混乱的testing。 (你可能会争辩说,它不应该是一个混乱,但让我们现实在这里)。

所以select仍然是你的select,但是我会争辩说,通过混合testing,你可以像使用单独的文件夹一样完成所有的任务,但是在保持整洁方面花费更less。

我更喜欢testing目录。 这确实意味着import变得更加困难。 为此,我有两个解决scheme:

  1. 使用setuptools。 然后,您可以将test_suite='tests.runalltests.suite'传递给setup() ,并且可以运行testing: python setup.py test
  2. 运行testing时设置PYTHONPATH: PYTHONPATH=. python tests/runalltests.py PYTHONPATH=. python tests/runalltests.py

以下是M2Crypto中代码的支持情况:

如果你喜欢用鼻子testing来运行testing,你可能需要做一些不同的事情。

我们用

应用程序/ SRC / code.py

应用程序/testing/ code_test.py

应用程序/文档/ ..

在每个testing文件中,我们在sys.path中插入“../src/”。 这不是最好的解决scheme,但工程。 我认为如果有人在java中使用maven之类的东西,那将会非常棒,它可以让你使用标准的约定,不pipe你在哪个项目上工作。

在C#中,我通常将testing分为单独的程序集。

在Python中 – 到目前为止 – 我倾向于编写doctests,其中testing位于函数的docstring中,或者将它们放在if __name__ == "__main__"底部的if __name__ == "__main__"块中。

当编写一个名为“foo”的包时,我会把unit testing放到一个单独的包“foo_test”中。 然后,模块和子包将与SUT包模块具有相同的名称。 例如,在foo_test.xy中find模块foo.xy的testing。每个testing包的__init__.py文件都包含一个AllTests套件,该套件包含该软件包的所有testing套件。 setuptools提供了一个方便的方法来指定主要的testing包,所以在“python setup.py develop”之后,你可以使用“python setup.py test”或者“python setup.py test -s foo_test.x.SomeTestSuite”只是一个特定的套件。

如果testing很简单,只需将它们放在文档string中 – 大多数Pythontesting框架将能够使用:

 >>> import module >>> module.method('test') 'testresult' 

对于其他更多涉及的testing,我会把它们放在../tests/test_module.py或在tests/test_module.py

我最近开始用Python编程,所以我还没有机会find最佳实践。 但是,我写了一个模块,find所有的testing并运行它们。

所以我有:

应用程序/
  appfile.py
testing/
  appfileTest.py

当我进入更大的项目时,我将不得不看看它是如何发展的。