How to run tests without installing package?
Question:
I have some Python package and some tests. The files are layed out following http://pytest.org/latest/goodpractices.html#choosing-a-test-layout-import-rules
Putting tests into an extra directory outside your actual application
code, useful if you have many functional tests or for other reasons
want to keep tests separate from actual application code (often a good
idea):
setup.py # your distutils/setuptools Python package metadata
mypkg/
__init__.py
appmodule.py
tests/
test_app.py
My problem is, when I run the tests py.test
, I get an error
ImportError: No module named ‘mypkg’
I can solve this by installing the package python setup.py install
but this means the tests run against the installed package, not the local one, which makes development very tedious. Whenever I make a change and want to run the tests, I need to reinstall, else I am testing the old code.
What can I do?
Answers:
Import the package using from .. import mypkg
. For this to work you will need to add (empty) __init__.py
files to the tests directory and the containing directory. py.test
should take care of the rest.
The normal approach for development is to use a virtualenv and use pip install -e .
in the virtualenv (this is almost equivalent to python setup.py develop
). Now your source directory is used as installed package on sys.path.
There are of course a bunch of other ways to get your package on sys.path for testing, see Ensuring py.test includes the application directory in sys.path for a question with a more complete answer for this exact same problem.
I know this question has been already closed, but a simple way I often use is to call pytest
via python -m
, from the root (the parent of the package).
$ python -m pytest tests
This works because -m
option adds the current directory to the python path, and hence mypkg
is detected as a local package (not as the installed).
See:
https://docs.pytest.org/en/latest/usage.html#calling-pytest-through-python-m-pytest
On my side, while developing, I prefer to run tests from the IDE (using a runner extension) rather than using the command line. However, before pushing my code or prior to a release, I like to use the command line.
Here is a way to deal with this issue, allowing you to run tests from both the test runner used by your IDE and the command line.
My setup:
-
IDE: Visual Studio Code
-
Testing: pytest
-
Extension (test runner): https://marketplace.visualstudio.com/items?itemName=LittleFoxTeam.vscode-python-test-adapter
-
Work directory structure (my solution should be easily adaptable to your context):
project_folder/
src/
mypkg/
__init__.py
appmodule.py
tests/
mypkg/
appmodule_test.py
pytest.ini <- Use so pytest can locate pkgs from ./src
.env <- Use so VsCode and its extention can locate pkgs from ./src
-
.env:
PYTHONPATH="${PYTHONPATH};./src;"
-
pytest.ini (tried with pytest 7.1.2):
[pytest]
pythonpath = . src
-
./src/mypkg/appmodule.py:
def i_hate_configuring_python():
return "Finally..."
-
./tests/mypkg/appmodule_test.py:
from mypkg import app_module
def test_demo():
print(app_module.i_hate_configuring_python())
This should do the trick
I have some Python package and some tests. The files are layed out following http://pytest.org/latest/goodpractices.html#choosing-a-test-layout-import-rules
Putting tests into an extra directory outside your actual application
code, useful if you have many functional tests or for other reasons
want to keep tests separate from actual application code (often a good
idea):setup.py # your distutils/setuptools Python package metadata mypkg/ __init__.py appmodule.py tests/ test_app.py
My problem is, when I run the tests py.test
, I get an error
ImportError: No module named ‘mypkg’
I can solve this by installing the package python setup.py install
but this means the tests run against the installed package, not the local one, which makes development very tedious. Whenever I make a change and want to run the tests, I need to reinstall, else I am testing the old code.
What can I do?
Import the package using from .. import mypkg
. For this to work you will need to add (empty) __init__.py
files to the tests directory and the containing directory. py.test
should take care of the rest.
The normal approach for development is to use a virtualenv and use pip install -e .
in the virtualenv (this is almost equivalent to python setup.py develop
). Now your source directory is used as installed package on sys.path.
There are of course a bunch of other ways to get your package on sys.path for testing, see Ensuring py.test includes the application directory in sys.path for a question with a more complete answer for this exact same problem.
I know this question has been already closed, but a simple way I often use is to call pytest
via python -m
, from the root (the parent of the package).
$ python -m pytest tests
This works because -m
option adds the current directory to the python path, and hence mypkg
is detected as a local package (not as the installed).
See:
https://docs.pytest.org/en/latest/usage.html#calling-pytest-through-python-m-pytest
On my side, while developing, I prefer to run tests from the IDE (using a runner extension) rather than using the command line. However, before pushing my code or prior to a release, I like to use the command line.
Here is a way to deal with this issue, allowing you to run tests from both the test runner used by your IDE and the command line.
My setup:
-
IDE: Visual Studio Code
-
Testing: pytest
-
Extension (test runner): https://marketplace.visualstudio.com/items?itemName=LittleFoxTeam.vscode-python-test-adapter
-
Work directory structure (my solution should be easily adaptable to your context):
project_folder/ src/ mypkg/ __init__.py appmodule.py tests/ mypkg/ appmodule_test.py pytest.ini <- Use so pytest can locate pkgs from ./src .env <- Use so VsCode and its extention can locate pkgs from ./src
-
.env:
PYTHONPATH="${PYTHONPATH};./src;"
-
pytest.ini (tried with pytest 7.1.2):
[pytest] pythonpath = . src
-
./src/mypkg/appmodule.py:
def i_hate_configuring_python(): return "Finally..."
-
./tests/mypkg/appmodule_test.py:
from mypkg import app_module def test_demo(): print(app_module.i_hate_configuring_python())
This should do the trick