Python单元测试在哪里?

Rea*_*nly 464 python unit-testing code-organization

如果您正在编写库或应用程序,那么单元测试文件会在哪里进行?

将测试文件与主应用程序代码分开是很好的,但将它们放入app根目录内的"tests"子目录中是很尴尬的,因为这会导致导入您将要测试的模块变得更加困难.

这里有最好的做法吗?

小智 189

对于文件module.py,通常应test_module.py按照Pythonic命名约定调用单元测试.

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

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

我更喜欢#1,因为它很容易找到测试并导入它们.无论您使用什么构建系统,都可以轻松配置为以#开头运行文件test_.实际上,用于测试发现默认unittest模式是test*.py.

  • [load_tests protocol](http://docs.python.org/2/library/unittest.html#load-tests-protocol)默认搜索名为test*.py的文件.此外,[这个谷歌的最高结果](http://docs.python-guide.org/en/latest/writing/tests/)和[本单元测试文档](http://docs.python.org/2/library /unittest.html#command-line-interface)都使用test_module.py格式. (12认同)
  • @juniper,按照你的想法,在编码时,module_test将出现在自动完成中.这可能令人困惑或烦人. (11认同)
  • 部署代码时,我们不希望将测试部署到生产位置.所以,当我们进行部署时,将它们放在一个目录"./tests/test_blah.py"中就很容易了.此外,一些测试采用样本数据文件,并且在测试目录中包含这些文件至关重要,以免我们部署测试数据. (11认同)
  • 使用foo_test.py可以在使用制表符完成时保存一两次击键,因为你没有一堆以'test_'开头的文件. (6认同)
  • @endolith,不在产品盒中测试代码是否有效(功能测试),仅在开发和质量检查上运行测试,如果我们有的话,可能还可以在暂存盒上运行测试。产品盒被锁定并可以访问生产数据库等,测试可能会意外地以不良方式访问此关键基础设施。最好不要将测试放在产品盒中,除非您试图做一些非常具体的事情,例如监视服务,此时我们谈论的是监视而不是单元测试。 (3认同)
  • @KevinJ.Rice 你不应该测试代码在你的生产地点工作吗? (2认同)
  • 我发现在主模块目录下发布测试非常有用,因为它允许我将代码实际发布到生产中(如果我愿意!),这允许用户在提交错误之前直接运行测试套件...... (2认同)

Ste*_*ing 59

只有1个测试文件

如果没有很多测试文件,将它放在顶级目录中是很好的(我认为这是一种pythonic(推荐)方式):

module/
    lib/
        __init__.py
        module.py
    test.py
Run Code Online (Sandbox Code Playgroud)

许多测试文件

如果有许多测试文件,请将其放在一个tests文件夹中:

python test.py
Run Code Online (Sandbox Code Playgroud)

但是如果你把测试放在unittest discovery文件夹中,测试不能unittest discovery在CLI中因为__init__.py 无法导入相关模块,所以我们可以使用nose,或者我们可以将一个父目录添加到python导入路径,为此我将创建一个

env.py

module/
    lib/
        __init__.py
        module.py
    tests/
        test_module.py
        test_module_function.py
Run Code Online (Sandbox Code Playgroud)

# test_module.py

import unittest
from lib import module

class TestModule(unittest.TestCase):
    def test_module(self):
        pass

if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

tests/在测试导入模块之前

test_module.py

# In top-level /module/ folder
python -m tests.test_module
python -m tests.test_module_function
Run Code Online (Sandbox Code Playgroud)

  • 我的结构与您在“许多测试文件”下概述的结构相同,但是当我尝试“from lib import module”时,我收到错误:“ImportError:没有名为“lib”的模块” (2认同)
  • @ShervinRad您需要在`module`文件夹中运行,而不是`lib`或`tests`文件夹中,python使用相对路径导入。 (2认同)

Cri*_*ian 50

通常的做法是将tests目录放在与模块/包相同的父目录中.因此,如果您的模块被称为foo.py,您的目录布局将如下所示:

parent_dir/
  foo.py
  tests/
Run Code Online (Sandbox Code Playgroud)

当然没有一种方法可以做到这一点.您还可以创建一个tests子目录并使用绝对导入导入模块.

无论你在哪里进行测试,我都会建议你用鼻子来测试它们.Nose在您的目录中搜索测试.这样,您可以将测试放在组织最有意义的地方.

  • 我想这样做,但我不能让它发挥作用.要运行测试,我在parent_dir中,并输入:"python tests\foo_test.py",并在foo_test.py中:"from ..foo import this,that,theother"that failed with:"ValueError:Attempted非包中的相对导入"parent_dir和test都有__init__.py,所以我不确定它们为什么不是包.我怀疑这是因为你从命令行运行的顶级脚本不能被视为一个包的一部分,即使它在带有__init__.py的目录中.那么我该如何运行测试呢?我今天在Windows上工作,祝福我的棉袜. (15认同)
  • 我的问题的一个解决方案,使用Python2.6或更新版本,我们使用以下命令从项目的根目录运行测试:python -m project.package.tests.module_tests(而不是python project/package/tests/module_tests.py) .这将测试模块的目录放在路径上,因此测试可以对其父目录进行相对导入以获取被测模块. (8认同)
  • 最好的方法 - 我发现 - 运行单元测试是安装你的库/程序然后用nose运行单元测试.我会推荐virtualenv和virtualenvwrapper来使这更容易. (4认同)
  • 谢谢凯西 - 但我在所有相关目录中都有一个__init__.py文件.我不知道我做错了什么,但是我的所有Python项目都遇到了这个问题,我无法理解为什么没有其他人这样做.哦,亲爱的. (4认同)
  • http://guide.python-distribute.org/example.html支持此安排 (3认同)

Pau*_*ndt 32

编写Pythoscope(http://pythoscope.org)时,我们遇到了同样的问题,它为Python程序生成单元测试.在我们选择目录之前,我们在python列表中对人们进行了测试,有很多不同的意见.最后,我们选择将"tests"目录放在与源代码相同的目录中.在该目录中,我们为父目录中的每个模块生成一个测试文件.

  • 真棒!只是在一些遗留代码上运行Pythoscope(伟大的徽标),这太棒了.即时最佳实践,您可以让其他开发人员填写现在失败的测试存根.现在把它连成竹子?:) (2认同)

Tho*_*ews 27

我也倾向于将我的单元测试放在文件本身中,就像Jeremy Cantrell上面说的那样,虽然我倾向于不将测试功能放在主体中,而是将所有内容放入

if __name__ == '__main__':
   do tests...
Run Code Online (Sandbox Code Playgroud)

块.这最终会将文档作为"示例代码"添加到文件中,以了解如何使用您正在测试的python文件.

我应该补充一下,我倾向于编写非常紧凑的模块/类.如果你的模块需要大量的测试,你可以将它们放在另一个中,但即便如此,我仍然会添加:

if __name__ == '__main__':
   import tests.thisModule
   tests.thisModule.runtests
Run Code Online (Sandbox Code Playgroud)

这使得任何阅读源代码的人都知道在哪里查找测试代码.


Jan*_*zny 17

每次在一段时间后,我发现自己检查了测试放置的话题,每一次多数建议库代码旁边有一个单独的文件夹结构,但我发现,每一个参数是相同的,时间不是那么令人信服.我最终将我的测试模块放在核心模块旁边.

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

当我移动东西时,我确实希望测试模块随代码一起移动; 如果它们位于单独的树中,则很容易丢失测试.老实说,迟早你会得到一个完全不同的文件夹结构,比如django,flask和许多其他文件夹.如果你不在乎,这很好.

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

我写的是:

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

如果一个:

一个单独的文件夹和维护其结构的额外努力可能更适合.没有人会抱怨您的测试部署到生产中.

但是,当它们与核心文件夹混合时,将测试排除在外也同样容易; 把它放在setup.py中:

find_packages("src", exclude=["*.tests", "*.tests.*", "tests.*", "tests"]) 
Run Code Online (Sandbox Code Playgroud)

如果b:

您可能希望 - 正如我们每个人所做的那样 - 您正在编写可重用的库,但大多数时候他们的生活与项目的生命紧密相关.能够轻松维护您的项目应该是一个优先事项.

然后,如果你的工作做得很好,你的模块是一个不错的选择另一个项目,它可能会被复制 - 不分叉或做成一个单独的库 - 这个新的项目,以及移动,在相同的文件夹结构旁边躺着测试与在一个单独的测试文件夹变成的混乱中进行钓鱼测试相比,这很容易.(你可能会说,首先它不应该是混乱,但让我们在这里是现实的).

所以选择仍然是你的,但我认为,通过混合测试,你可以实现与单独的文件夹相同的所有东西,但是更少的努力保持整洁.

  • 正如我在回答中所写,我通常不单独测试。但。将测试放入分发包可能会导致执行您通常不希望在生产环境中执行的内容(例如某些模块级代码)。这当然取决于测试的编写方式,但为了安全起见,您可以将它们放在一边,没有人会错误地运行有害的东西。我不反对在发行版中包含测试,但我知道根据经验,它更安全。将它们放在单独的文件夹中可以非常容易地不将它们包含在 dist 中。 (2认同)

Joh*_*kin 14

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

from .. import foo
Run Code Online (Sandbox Code Playgroud)

导入MyApp.foo模块.

  • “ValueError:尝试在非包中进行相对导入” (6认同)

dwe*_*ook 12

我不相信有一个既定的"最佳实践".

我将测试放在应用程序代码之外的另一个目录中.然后我在运行所有测试之前将主app应用程序目录添加到sys.path(允许您从任何地方导入模块)中我的测试运行器脚本(还有其他一些东西).这样我就不必在发布时从主代码中删除测试目录,节省了我的时间和精力,如果这么少的话.

  • *然后我将主应用程序目录添加到sys.path *问题是如果您的测试包含一些帮助程序模块(例如测试Web服务器),并且您需要从适当的测试中导入此类帮助程序模块。 (2认同)

小智 11

根据我在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]
Run Code Online (Sandbox Code Playgroud)

这样,当您使用rpm打包这些库时,您只需打包主库模块(仅限).这有助于维护,特别是在敏捷环境中.

  • 我意识到这种方法的一个潜在优点是测试可以作为自己的独立应用程序进行开发(甚至可以进行版本控制)。当然,每一个优点都有一个缺点——保持对称性基本上就是进行“复式记账”,并且使重构变得更加繁琐。 (2认同)

Ara*_*ash 10

我建议你在GitHub上查看一些主要的Python项目并获得一些想法.

当您的代码变大并添加更多库时,最好在setup.py所在的同一目录中创建一个测试文件夹,并镜像每个测试类型的项目目录结构(unittest,integration,...)

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

myPackage/
    myapp/
       moduleA/
          __init__.py
          module_A.py
       moduleB/
          __init__.py
          module_B.py
setup.py
Run Code Online (Sandbox Code Playgroud)

添加测试文件夹后,您将拥有如下目录结构:

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
Run Code Online (Sandbox Code Playgroud)

许多正确编写的Python包使用相同的结构.一个很好的例子是Boto包.检查https://github.com/boto/boto


Dal*_*idy 7

我是怎么做的......

文件夹结构:

project/
    src/
        code.py
    tests/
    setup.py
Run Code Online (Sandbox Code Playgroud)

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

setup.py develop
Run Code Online (Sandbox Code Playgroud)

这将我的项目添加到站点包中,指向我的工作副本.为了运行我的测试我使用:

setup.py tests
Run Code Online (Sandbox Code Playgroud)

使用我配置的测试运行器.


小智 5

我更喜欢顶级测试目录。这确实意味着进口变得更加困难。为此,我有两个解决方案:

  1. 使用设置工具。然后,你可以通过test_suite='tests.runalltests.suite'进入setup(),并且可以简单地运行测试:python setup.py test
  2. 运行测试时设置 PYTHONPATH: PYTHONPATH=. python tests/runalltests.py

以下是 M2Crypto 中的代码如何支持这些东西:

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