python unittest目录结构-无法导入src代码

toe95027  于 2023-01-08  发布在  Python
关注(0)|答案(1)|浏览(176)

我的项目中有以下文件夹结构:

my-project
   src/
       __init__.py
       script.py
   test/
       __init__.py
       test_script.py

理想情况下,我希望有一个单独的文件夹来存放所有的单元测试。我的test_script.py看起来像这样:

from src.script.py import my_object

class TestClass(unittest.TestCase):
    
    def test_script_object(self):
        # unit test here
        pass

if __name__ == 'main':
    unittest.main()

当我尝试运行脚本(使用python test_script.py)时,我收到以下错误:

Traceback (most recent call last):
  File "test_script.py", line 4, in <module>
    from src.script import my_object
ModuleNotFoundError: No module named 'src'

我遵循from this other thread的指令,甚至尝试将src附加到sys路径(这迫使我改变在项目其余部分导入的方式),当我不尝试将src附加到sys路径时,我的两个__init__.py文件都是空的。
我用的是python 3.8。
有人有什么建议吗?我刚开始接触python的单元测试,所以也许有更好的结构或者其他我不知道的约定。提前感谢你们的帮助!

gfttwv5a

gfttwv5a1#

一般来说,任何为了运行测试而修改sys.path的指令都是在向错误的方向发送,您的测试工具应该能够发现您的测试和应用程序代码,而不需要这种黑客行为。
我通常使用pytest来运行我的测试。我将像这样构造您的示例:

my-project/
├── src
│   ├── conftest.py
│   └── myproject
│       ├── __init__.py
│       └── script.py
└── tests
    ├── __init__.py
    └── test_script.py

假设src/myproject/script.py如下所示:

def double(x: int):
    return x*2

tests/test_script.py看起来像这样:

import myproject.script

def test_double():
    res = myproject.script.double(2)
    assert res == 4

我可以从my-project目录运行测试,只需运行pytest

$ pytest
========================================== test session starts ==========================================
platform linux -- Python 3.11.1, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/lars/tmp/python/my-project
collected 1 item

tests/test_script.py .                                                                            [100%]

=========================================== 1 passed in 0.00s ===========================================

在这个设置中,文件src/conftest.py允许pytest自动发现你的应用程序代码的位置,或者,你可以在你的pyproject.toml文件中这样指定:

[tool.pytest.ini_options]
pythonpath = [
  "src"
]

如果您编写的是如问题中所示的unittest样式的测试,pytest也可以工作;如果tests/test_script.py如下所示,上述行为将是相同的:

import unittest
import myproject.script

class TestScript(unittest.TestCase):
    def test_double(self):
        res = myproject.script.double(2)
        self.assertEqual(res, 4)

if __name__ == '__main__':
    unittest.main()

(But我更喜欢pytest更简单的语法。)
可能有用的阅读:

如果你真的想使用unittest,你可以使用相同的目录布局,但是你需要更新sys.path以使它正确运行。

PYTHONPATH=$PWD/src python -m unittest

这将自动发现所有测试并运行它们。您可以像这样运行单个测试:

PYTHONPATH=$PWD/src python -m tests.test_script

如果使用更简单的目录布局,则可以避免修改sys.path

my-project/
├── myproject
│   ├── __init__.py
│   └── script.py
└── tests
    ├── __init__.py
    └── test_script.py

当从my-project目录运行时,pytestpython -m unittest都将正确地发现并运行您的测试,而不需要任何路径修改。

相关问题