对于一个简单的Python模块来说,非常常见的目录结构似乎是将单元测试分离到它们自己的测试目录中:

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py
    setup.py
    etc.

我的问题很简单,实际运行测试的通常方式是什么?我怀疑这对每个人来说都是显而易见的,除了我,但你不能只是从测试目录运行python test_antigravity.py,因为它的导入antigravity将失败,因为模块不在路径上。

我知道我可以修改PYTHONPATH和其他与搜索路径相关的技巧,但我不能相信这是最简单的方法——如果您是开发人员,这很好,但如果用户只是想检查测试是否通过,那么期望他们使用这种方法是不现实的。

另一种替代方法是将测试文件复制到另一个目录中,但这似乎有点愚蠢,并且没有注意到将它们放在一个单独的目录中。

那么,如果您刚刚下载源代码到我的新项目,您将如何运行单元测试?我更喜欢这样的答案:“要运行单元测试,请执行x。”


当前回答

这个BASH脚本将从文件系统中的任何位置执行python unittest test目录,无论您在哪个工作目录中。

当你在。/src或。/example工作目录下,并且你需要一个快速的单元测试时,这是很有用的:

#!/bin/bash

this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

python -m unittest discover -s "$readlink"/test -v

在生产过程中,不需要test/__init__.py文件来增加包/内存开销。

其他回答

我通常在项目目录中创建一个“运行测试”脚本(对于源目录和测试都是通用的),用于加载我的“所有测试”套件。这通常是样板代码,所以我可以在项目之间重用它。

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

有了这个设置,你确实可以在你的测试模块中包含反重力。缺点是你需要更多的支持代码来执行一个特定的测试…我每次都把它们都运行一遍。

对于用户来说,最简单的解决方案是提供一个可执行脚本(runtests.py或类似的脚本),该脚本引导必要的测试环境,包括(如果需要的话)将根项目目录添加到sys. py。临时道路。这并不需要用户设置环境变量,类似这样的东西在引导脚本中工作得很好:

import sys, os

sys.path.insert(0, os.path.dirname(__file__))

然后你给用户的指令可以像“python runtests.py”一样简单。

当然,如果你需要的路径确实是os.path.dirname(__file__),那么你不需要将它添加到sys. path.dirname(__file__)。道路;Python总是将当前运行脚本的目录放在sys. exe的开头。路径,因此根据您的目录结构,将runtests.py定位到正确的位置可能就足够了。

此外,Python 2.7+中的unittest模块(在Python 2.6及更早的版本中被反向移植为unittest2)现在内置了测试发现,所以如果你想自动化测试发现,nose不再是必要的:你的用户指令可以像Python -m unittest discover一样简单。

如果你运行“python setup.py develop”,那么包就会在路径中。但你可能不想这样做,因为你可能会感染你的系统python安装,这就是virtualenv和buildout等工具存在的原因。

如果你使用VS Code,并且你的测试与你的项目位于同一级别,那么运行和调试你的代码就不能开箱即用。你能做的就是改变启动方式。json文件:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "program": "${file}",
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.env",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }    
    ]
}

这里的关键行是envFile

"envFile": "${workspaceRoot}/.env",

在项目的根目录中添加.env文件

在.env文件中添加项目根目录的路径。这将临时添加

PYTHONPATH = C: \ \ PYTHON项目\ \ ROOT_DIRECTORY

路径到你的项目,你将能够使用调试单元测试从VS Code

我也遇到了同样的问题,使用了一个单独的单元测试文件夹。根据上述建议,我将绝对源路径添加到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