Py.test masks lack of import
I have a piece of code with an extensive test suite that we run using py.test. I recently ran into an issue where a new module had to import another module in order to work correctly. However, since this module was imported elsewhere in the test suite, py.test did not throw an error. Only many years later did this error appear. I've created a minimal reproducible example.
Minimal reproducible example
Project structure:
set.py
fail/
__init__.py
thing.py
other.py
tests/
test_thing.py
test_other.py
If these files contain the following code:
fail/thing.py
:
import fail
def needs_do_it():
return fail.other.do_it() + 100
fail/other.py
:
def do_it():
return 100
tests/test_thing.py
:
import fail.thing
def test_needs_do_it():
assert fail.thing.needs_do_it() == 200
tests/test_other.py
:
import fail.other
def test_do_it():
assert fail.other.do_it() == 100
Expected behavior
If you try to run the function needs_do_it
, you should get an error as it only imported fail
, not fail.other
:
>>> import fail.thing
>>> fail.thing.needs_do_it()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "fail/thing.py", line 4, in needs_do_it
return fail.other.do_it() + 100
AttributeError: 'module' object has no attribute 'other'
I would expect a test run under py.test to expose this error on import. However, it completely masks this problem.
Actual behavior
Because it test_other.py
imports test.other
, py.test masks the error.
$ py.test
========== test session starts ==========
platform darwin -- Python 2.7.13, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /Users/eswanson/Sandbox/pytest-test, inifile:
collected 2 items
tests/test_other.py .
tests/test_thing.py .
========== 2 passed in 0.01 seconds ==========
My question
My quesiton has three parts:
- What is the cause of this problem?
- Is this the expected behavior for py.test, or something I should be concerned about?
- Is there anything I can do for the pytest user for me to get more guarantees that I won't import imports in the future.
The same happens when you import fail.other
into the Python shell, as Python modules are single:
>>> import fail.thing
>>> fail.thing.needs_do_it()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/florian/tmp/fo/fail/thing.py", line 4, in needs_do_it
return fail.other.do_it() + 100
AttributeError: module 'fail' has no attribute 'other'
>>> import fail.other
>>> fail.thing.needs_do_it()
200