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

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

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

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

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

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


当前回答

*nix系统(macOS, Linux)的简单解决方案;也可能是Git bash在Windows上。

PYTHONPATH=$PWD python test/test_antigravity.py

Print语句很容易工作,不像pytest test/test_antigravity.py。对于“脚本”来说,这是一种完美的方法,但对于单元测试来说却不是。

当然,我想做一个适当的自动化测试,我会考虑使用适当设置的pytest。

其他回答

从你链接的文章中:

Create a test_modulename.py file and put your unittest tests in it. Since the test modules are in a separate directory from your code, you may need to add your module’s parent directory to your PYTHONPATH in order to run them: $ cd /path/to/googlemaps $ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps $ python test/test_googlemaps.py Finally, there is one more popular unit testing framework for Python (it’s that important!), nose. nose helps simplify and extend the builtin unittest framework (it can, for example, automagically find your test code and setup your PYTHONPATH for you), but it is not included with the standard Python distribution.

也许你应该像它所暗示的那样看看鼻子?

这个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文件来增加包/内存开销。

项目中的单元测试有setup.py文件。试一试:

python3 setup.py build

and

python3 setup.py develop --user

做配置路径之类的工作。试一试!

在我看来,最好的解决方案是使用unittest命令行界面,它会将目录添加到sys. exe目录。路径,因此您不必(在TestLoader类中完成)。

例如,对于这样的目录结构:

new_project
├── antigravity.py
└── test_antigravity.py

你可以直接运行:

$ cd new_project
$ python -m unittest test_antigravity

对于像你这样的目录结构:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

在测试包中的测试模块中,可以像往常一样导入反重力包及其模块:

# import the package
import antigravity

# import the antigravity module
from antigravity import antigravity

# or an object inside the antigravity module
from antigravity.antigravity import my_object

运行单个测试模块:

要运行单个测试模块,在本例中为test_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

引用测试模块的方法与导入测试模块的方法相同。

运行单个测试用例或测试方法:

你也可以运行一个TestCase或者一个测试方法:

$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method

运行所有测试:

你也可以使用测试发现,它会发现并运行所有的测试,它们必须是命名为test*.py的模块或包(可以使用-p,——pattern标志进行更改):

$ cd new_project
$ python -m unittest discover
$ # Also works without discover for Python 3
$ # as suggested by @Burrito in the comments
$ python -m unittest

这将运行测试包中的所有test*.py模块。

Python unittest模块的解决方案/示例

鉴于以下项目结构:

ProjectName
 ├── project_name
 |    ├── models
 |    |    └── thing_1.py
 |    └── __main__.py
 └── test
      ├── models
      |    └── test_thing_1.py
      └── __main__.py

你可以使用python project_name从根目录运行你的项目,它调用ProjectName/project_name/__main__.py。


要使用python test运行测试,有效地运行ProjectName/test/__main__.py,您需要执行以下操作:

1)通过添加__init__.py文件将您的test/models目录转换为一个包。这使得子目录中的测试用例可以从父测试目录中访问。

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2)在test/__main__.py中修改系统路径以包含project_name目录。

# ProjectName/test/__main__.py

import sys
import unittest

sys.path.append('../project_name')

loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)

现在您可以在测试中成功地从project_name导入内容。

# ProjectName/test/models/test_thing_1.py    

import unittest
from project_name.models import Thing1  # this doesn't work without 'sys.path.append' per step 2 above

class Thing1TestCase(unittest.TestCase):

    def test_thing_1_init(self):
        thing_id = 'ABC'
        thing1 = Thing1(thing_id)
        self.assertEqual(thing_id, thing.id)