Python单元测试模块导入错误:找不到<...>模块。

5

我尝试使用flaskunittest创建一个简单的Python项目。结构相当简单:

classes
  |-sysinfo
      |static
      |templates
         |- index.html
         |- layout.html
      |__init__.py
      |sysinfo.py
      |printinfo.py
  tests
  |test_sysinfo.py
README.md
requirments.txt

非常简单的类在printinfo.py中:
 #!/usr/bin/python
import psutil
import json
class SysInfo:
.......
    def displayInfo(self):
        .......
        return json.dumps(self.__data)

以下是使用 sysinfo.py 运行的简单 Flask 服务器:

from flask import Flask, flash, redirect, render_template, request, session, abort
from printinfo import SysInfo
import json
obj1 = SysInfo("gb")
app = Flask(__name__)
@app.route('/')
def index():
    var = json.loads(obj1.displayInfo())
    return render_template('index.html',**locals())
@app.route('/healthcheck')
def healthcheck():
    return "Ok"
@app.route("/api/all")
def all():
    return obj1.displayInfo()
if __name__ == '__main__':
   app.run(host='0.0.0.0', port=80)
del obj1

我使用Python命令行运行了sysinfo.py,位于classes/sysinfo文件夹中,一切正常。

因此,我决定为我的应用程序运行单元测试。在classes/tests(也尝试过classes/sysinfo/tests)文件夹中添加了test_sysinfo.py文件,其中包含以下代码:

import unittest
import printinfo
from sysinfo import sysinfo
import json
import sys
class TestFlaskApi(unittest.TestCase):
    def setUp(self):
        self.app = sysinfo.app.test_client()
    def simple_test(self):
        response = self.app.get('/health')
        self.assertEqual(
            json.loads(response.get_data().decode(sys.getdefaultencoding())),
            {'healthcheck': 'ok'}
        )
if __name__ == "__main__":
    unittest.main()

当我启动它时,我看到了错误:

Error Traceback (most recent call last):
   File "\Python\Python37-32\lib\unittest\case.py", line 59, in testPartExecutor
     yield   File "\Python\Python37-32\lib\unittest\case.py", line 615, in run
     testMethod()   File "\Python\Python37-32\lib\unittest\loader.py", line 34, in testFailure
     raise self._exception ImportError: Failed to import test module: test_sysinfo Traceback (most recent call last):   File
 "\Python\Python37-32\lib\unittest\loader.py", line 154, in
 loadTestsFromName
     module = __import__(module_name)   File "\classes\sysinfo\tests\test_sysinfo.py", line 2, in <module>
     import printinfo ModuleNotFoundError: No module named 'printinfo'

我阅读了几篇文章,包括一些在StackOverflow上的主题,以便更好地理解项目结构。我尝试创建 setup.pysetup.cfg。我已经使用这个设置成功启动了它,但测试仍然无法正常工作。

请您帮助我找到适用于我的情况的最小设置?我找到的所有材料都是针对特定情况或过于笼统。我无法将其应用于我的情况。


这是一个 sys.path 问题。如果你通过 python classes/tests/test_sysinfo.py 来运行测试,classes/sysinfo 目录不会被包含在 sys.path 中,因此 Python 无法导入 printinfo 模块。若要避免进一步修改项目结构,你可以显式地将该目录添加到 sys.path 中作为解决方法:PYTHONPATH=classes/sysinfo/ python classes/tests/test_sysinfo.py - hoefling
然而,看起来你的导入有些混乱。sysinfo是一个包,所以你应该通过 from sysinfo import printinfo 导入 printinfo(就像你已经对另一个模块做到了:from sysinfo import sysinfo)。修正后,将 classes 添加到 sys.path(因为它是 sysinfo 包的父目录),导入问题就应该解决了:PYTHONPATH=classes python classes/tests/test_sysinfo.py - hoefling
我尝试了一下,现在又出现了一个与代码相关的错误,模块错误缺失。谢谢@hoefling,我已经开始重构代码,从setup.py运行我的代码作为模块。阅读手册并尝试将其适应我的实际情况。 - Dmytro
我已经准备放弃了(根据文档决定在__init__.py中初始化应用程序。以下是代码:`def create_app(test_config=None): # create and configure the app app = Flask(name, instance_relative_config=True) app.config.from_mapping( SECRET_KEY='dev' )from . import printinfo # Create printenv class instance obj1 = printinfo.SysInfo("gb")`同样的错误... `flask.cli.NoAppException: 在导入“sysinfo”时出现ImportError:` - Dmytro
你能否编辑问题,添加新的代码片段和错误追踪? - hoefling
2个回答

0

按照 Flask 教程,我编辑了 __init__.py 文件以从这里启动应用程序:

from flask import Flask, flash, redirect, render_template, request, session, abort
from . import printinfo
import json
import os

obj1 = printinfo.SysInfo("gb")

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY='dev'
    )

    obj1 = printinfo.SysInfo("gb")

    @app.route('/')
    def index():
        var = json.loads(obj1.displayInfo())
        return render_template('index.html', **locals())

    @app.route('/healthcheck')
    def healthcheck():
        return "Ok"

    @app.route("/api/all")
    def all():
        return obj1.displayInfo()

    #del obj1
    return app

同时,Flask还需要设置环境变量: 对于Linux和Mac:

export FLASK_APP=sysinfo
export FLASK_ENV=development

对于 Windows cmd,请使用 set 而不是 export:

set FLASK_APP=sysinfo
set FLASK_ENV=development

然后运行应用程序:

flask run

由于开发环境设置,它在本地主机的5000端口上运行应用程序。无论如何,我需要在__init__.py中添加from . import printinfo

尚未尝试测试,但认为应该可以工作。如果有兴趣,很快会更新。


0
刚刚按照 Flask 教程做了一遍,创建了 conftest.pytest_factory.py。使用 pytest 运行成功:
import pytest
from sysinfo import create_app
from sysinfo import printinfo

@pytest.fixture
def app():
    app = create_app({
        'TESTING': True
    })

    with app.app_context():
        printinfo.SysInfo("gb")

    yield app

可能可以使用相同的设置与unittest一起使用。没有尝试过。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接