unittest,在本地工作,但不在远程服务器上工作,没有名为 x.__main__ 的模块; 'x'是一个包,不能直接执行

unittest, works locally, but not on a remote server, no module named x.__main__; 'x' is a package and cannot be directly executed

我正在为我的 Python 包开发 Jenkins CI/CD 管道。我的项目文件层次结构如下:

project/
- package_name
  - file1.py
  - file2.py
  - etc...
- tests
  - unit
    - __main__.py
    - __init__.py
    - test1.py
    - test2.py

所有单元测试(我正在使用 unittest)都是 运行 使用单个命令

python -m tests.unit

通过添加 __init__.py 以下内容:

内容

import os
os.chdir(os.path.dirname(os.path.abspath(__file__)))

__main__.py 看起来像这样

内容

import unittest
import sys

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

loader = unittest.TestLoader()
start_dir = '.'
suite = loader.discover(start_dir)
runner = unittest.TextTestRunner(verbosity=2).run(suite)

首先,路径更改为./tests/unit。之后,将顶层目录添加到导入路径中,以便可以在测试中导入包。这在我的个人笔记本电脑 (Python 3.6.4) 上按预期工作(即,所有休息由项目目录顶部的 运行ning python -m test.unit 执行)。

但是,当我在远程 Jenkins 服务器(Python 3.6.4)上使用相同的技巧时,我收到以下错误:

no module named test.unit.__main__; 'test.unit' is a package and cannot be directly executed

我已经研究了这个问题,但是 none 提议的解决方案似乎适用于我的情况。

我如何修改我的代码以在 unittest 中创建一个测试套件,这将 运行 在本地和远程没有任何问题?

编辑 我尝试修改 PYTHONPATH 变量,但没有成功

我可以 运行 使用此命令进行测试:

python -m unittest discover

您永远不需要 运行 os.chdir 或附加到 sys.path 只是为了 运行 您的测试。

我复制了你的项目结构,像这样:

.
├── package
│   └── module.py
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_module.py

请注意 tests/ 下的每个目录都有一个 __init__.py 文件,该文件实际上是空的。它只需要存在。它的存在使该目录成为一个模块。有关更多用例,请阅读此 answer.

你不需要 __main__.py。那是当你想从命令行 运行 python3 -m package 时(而不是 python3 package/module.py 或类似的东西)。看到这个 answer.

在这种情况下,unittest 只需要测试目录中的 __init__.py 文件即可正常工作。

每个测试文件的名称以 test_ 开头也很重要,因为这是 unittest 查找的命名约定。

作为参考,module.py 的内容如下所示:

def method():
    return True

test_module.py 的内容如下所示:

from package.module import method
from unittest import TestCase

class TestMethod(TestCase):
    def test_method(self):
        self.assertTrue(method())

对您的代码进行这些修改将使您能够 运行 在 unittest 中测试套件,而不会在本地和远程出现任何问题。

1。为什么它不起作用?

1.1。关于 python -m__main__.py

当你 运行 python -m tests.unit 时,python 解释器 运行 的代码是这样的

tests.__init__.py
tests.unit.__init__.py
tests.unit.__main__.py

1.2。重现错误

现在,如果您删除 __main__.py,您将收到以下错误:

No module named tests.unit.__main__; 'tests.unit' is a package and cannot be directly executed

这与您收到的消息几乎相同。如果您的 sys.path 中有一个文件夹,其中包含名为 test 的文件夹,其结构如下(注意:test 文件夹不在 prular 中,并且没有 __main__.py !)

test
├── __init__.py
└── unit
    └── __init__.py

和运行命令

python -m test.unit

python 解释器尝试 运行 的顺序是

test.__init__.py
test.unit.__init__.py
test.unit.__main__.py <-- missing!

由于缺少 test.unit.__main__.py,您将收到错误消息

No module named test.unit.__main__; 'test.unit' is a package and cannot be directly executed

这是您收到的错误消息。因此,您的错误消息的原因很可能是,您在 sys.path 目录中的某处有一个名为 test 的目录,其结构如上所示,并且您正在尝试调用 python -m test.unit 而不是python -m tests.unit.

2。如何让它发挥作用?

  • 删除您在 __init__.py__main__.py 中使用的 os.chdirsys.path.append 技巧。至少,python unittest 工作不需要它们。
  • 使用 documentation 中显示的模式创建单元测试(通过子类化 unittest.TestCase)
  • 运行 你的单元测试
python -m unittest