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

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

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

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

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

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


当前回答

如果没有一些巫术,就不能从父目录导入。下面是另一种至少适用于Python 3.6的方法。

首先,创建一个包含以下内容的test/context.py文件:

import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

然后在test/test_antigravity.py文件中导入如下内容:

import unittest
try:
    import context
except ModuleNotFoundError:
    import test.context    
import antigravity

请注意,这个try-except子句的原因是

导入测试。当使用“python test_antigravity.py”运行时,上下文将失败 在new_project目录下使用"python -m unittest"运行时导入context失败。

通过这种诡计,他们都成功了。

现在你可以运行test目录下的所有测试文件:

$ pwd
/projects/new_project
$ python -m unittest

或者运行一个单独的测试文件:

$ cd test
$ python test_antigravity

好吧,这并不比在test_antigravity。py中包含context。py的内容漂亮多少,但也许会漂亮一点。欢迎提出建议。

其他回答

如果没有一些巫术,就不能从父目录导入。下面是另一种至少适用于Python 3.6的方法。

首先,创建一个包含以下内容的test/context.py文件:

import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

然后在test/test_antigravity.py文件中导入如下内容:

import unittest
try:
    import context
except ModuleNotFoundError:
    import test.context    
import antigravity

请注意,这个try-except子句的原因是

导入测试。当使用“python test_antigravity.py”运行时,上下文将失败 在new_project目录下使用"python -m unittest"运行时导入context失败。

通过这种诡计,他们都成功了。

现在你可以运行test目录下的所有测试文件:

$ pwd
/projects/new_project
$ python -m unittest

或者运行一个单独的测试文件:

$ cd test
$ python test_antigravity

好吧,这并不比在test_antigravity。py中包含context。py的内容漂亮多少,但也许会漂亮一点。欢迎提出建议。

如果您正在寻找命令行解决方案:

基于以下目录结构(使用专用源目录进行概括):

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添加更多目录。

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

我注意到,如果您从“src”目录运行unittest命令行接口,那么导入可以正常工作,无需修改。

python -m unittest discover -s ../test

如果你想把它放在项目目录下的批处理文件中,你可以这样做:

setlocal & cd src & python -m unittest discover -s ../test

如果在测试目录中有多个目录,则必须向每个目录添加__init__.py文件。

/home/johndoe/snakeoil
└── test
    ├── __init__.py        
    └── frontend
        └── __init__.py
        └── test_foo.py
    └── backend
        └── __init__.py
        └── test_bar.py

然后一次运行所有测试,运行:

python -m unittest discover -s /home/johndoe/snakeoil/test -t /home/johndoe/snakeoil

来源:python -m unittest -h

  -s START, --start-directory START
                        Directory to start discovery ('.' default)
  -t TOP, --top-level-directory TOP
                        Top level directory of project (defaults to start
                        directory)