ModuleNotFoundError with pytest

后端 未结 6 719
时光说笑
时光说笑 2021-02-12 11:05

I want my tests folder separate to my application code. My project structure is like so

myproject/
  myproject/
    myproject.py
    moduleone.py
  tests/
    my         


        
相关标签:
6条回答
  • 2021-02-12 11:21

    Kept everything same and just added a blank test file at the root folder .. Solved

    Here are the findings, this problem really bugged me for a while. My folder structure was

    mathapp/
        - server.py  
        - configuration.py 
        - __init__.py 
        - static/ 
           - home.html  
    tests/            
        - functional 
           - test_errors.py 
        - unit  
           - test_add.py
    

    and pytest would complain with the ModuleNotFoundError.

    I introduced a mock test file at the same level as mathsapp and tests directory. The file contained nothing. Now pytest does not complain.

    Result without the file

    $ pytest
    ============================= test session starts =============================
    platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
    rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
    collected 1 item / 1 error
    
    =================================== ERRORS ====================================
    _______________ ERROR collecting tests/functional/test_func.py ________________
    ImportError while importing test module 'C:\mainak\workspace\0github\python-rest-app-cont\tests\functional\test_func.py'.
    Hint: make sure your test modules/packages have valid Python names.
    Traceback:
    tests\functional\test_func.py:4: in <module>
        from mathapp.service import sum
    E   ModuleNotFoundError: No module named 'mathapp'
    =========================== short test summary info ===========================
    ERROR tests/functional/test_func.py
    !!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
    ============================== 1 error in 0.24s ===============================
    

    Results with the file

    $ pytest
    ============================= test session starts =============================
    platform win32 -- Python 3.8.2, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
    rootdir: C:\mak2006\workspace\0github\python-rest-app-cont
    collected 2 items
    
    tests\functional\test_func.py .                                          [ 50%]
    tests\unit\test_unit.py .                                                [100%]
    
    ============================== 2 passed in 0.11s ==============================
    
    0 讨论(0)
  • 2021-02-12 11:22

    So it seems that the sys.path has to include the application directory rather than the project root folder containing the application directory and test directory.

    So in my case /my/local/path/myproject/myproject/ had to be in sys.path rather than /my/local/path/myproject/.

    Then I could run pytest in /my/local/path/myproject/ (didn't need python -m pytest). This meant that the modules within /myproject/myproject/ could find each other and the tests as well without any namespace nesting.

    So my tests looked like

     from moduleone import ModuleOne
     import pytest
    
     def test_fun():
         assert ModuleOne.example_func() == True
    

    That said, there seem to be many gotchas, so I have no idea if this is correct..

    0 讨论(0)
  • 2021-02-12 11:33

    Solution: use the PYTHONPATH env. var

    PYTHONPATH=. pytest
    

    As mentioned by @J_H, you need to explicitly add the root directory of your project, since pytest only adds to sys.path directories where test files are (which is why @Mak2006's answer worked.)


    Good practice: use a Makefile or some other automation tool

    If you are lazy and do not want to type that long command all the time, one option is to create a Makefile in your project's root dir with, e.g., the following:

    .PHONY: install test
    
    default: test
    
    install:
        pip install --upgrade .
    
    test:
        PYTHONPATH=. pytest
    

    Which allows you to simply run:

    make test
    

    or (even shorter)

    make
    

    Another common alternative is to use some standard testing tool, such as tox.

    0 讨论(0)
  • 2021-02-12 11:33

    Not sure if this solution was specific to my problem, but I simply add __init__.py to my tests folder and that solved the problem.

    0 讨论(0)
  • 2021-02-12 11:42

    I ran into this issue as well and am using poetry for dependency management and direnv for my project specific environment variables. Please note, I am relatively new to Python so I don't know if this is the correct fix.

    Here is my entire .envrc file:

    layout_poetry() {
      if [[ ! -f pyproject.toml ]]; then
        log_error 'No pyproject.toml found.  Use `poetry new` or `poetry init` to create one first.'
        exit 2
      fi
    
      local VENV=$(poetry env list --full-path | cut -d' ' -f1)
      if [[ -z $VENV || ! -d $VENV/bin ]]; then
        log_error 'No created poetry virtual environment found.  Use `poetry install` to create one first.'
        exit 2
      fi
      VENV=$VENV/bin
      export VIRTUAL_ENV=$(echo "$VENV" | rev | cut -d'/' -f2- | rev)
      export POETRY_ACTIVE=1
      PATH_add "$VENV"
    }
    
    layout poetry
    export PYTHONDONTWRITEBYTECODE=1
    export PYTHONPATH="$PWD/project_name"
    

    I don't know if I need to layout poetry because it is supposed to be creating virtual environments for us already but this is what I coworker recommended so I went with it. Layout poetry also didn't work without that function and it didn't like when I added it to my zshenv so I added it here.

    For this specific question, the last line is the money maker.

    0 讨论(0)
  • 2021-02-12 11:43

    Be sure to include . dot in the $PYTHONPATH env var.

    You can use this code fragment to debug such issues:

    import pprint
    import sys
    pprint.pprint(sys.path)
    

    Your question managed to use myproject at three different levels. At least during debugging you might want to use three distinct names, to reduce possible confusion.

    0 讨论(0)
提交回复
热议问题