'python unittest ModuleNotFoundError: No module named <...>

I tried to crate simple Python project with flask and unittest. Structure is quite simple:

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

Very simple class in printinfo.py:

 #!/usr/bin/python
import psutil
import json
class SysInfo:
.......
    def displayInfo(self):
        .......
        return json.dumps(self.__data)

And simple flask server run with sysinfo.py:

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

I run it with python sysinfo.py staying in classes/sysinfo folder and everything works ok.

So I decided to run unittest for my application. Put in classes/tests ( also tried classes/sysinfo/tests) file test_sysinfo.py with code:

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()

And when I started it I can see error:

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'

I read several articles, some topics here on StackOverflow for my understanding it's related to project structure. I tried to create setup.py and setup.cfg. I managed to start it with this setup, but test still didn't work.

Could you please help me with minimum setup applicable for my case? All the material I found had written for specific case or too general. I cannot apply it for my case.



Solution 1:[1]

Follow flask tutorial I edit __init__.py file to start app from here:

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

Also environment variables should be set for Flask: For Linux and Mac:

export FLASK_APP=sysinfo
export FLASK_ENV=development

For Windows cmd, use set instead of export:

set FLASK_APP=sysinfo
set FLASK_ENV=development

And run application:

flask run

It run application on localhost on port 5000 since development env set. Anyway I needed to add from . import printinfo into __init__.py.

Didn't try test, but think it should work. If interesting will update soon.

Solution 2:[2]

Just followed Flask tutorial. Created conftest.py and test_factory.py. Run Ok with 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

Probably the same setup could be used with unittest. Didn't try.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dmytro
Solution 2 Dmytro